From 5c1d767a95709de6f487dc535976ef6abb8a76e7 Mon Sep 17 00:00:00 2001 From: Sebastien Ros Date: Fri, 1 Feb 2013 11:55:35 -0800 Subject: [PATCH] Adding Media Gallery Field --HG-- branch : 1.x --- .../Drivers/MediaGalleryFieldDriver.cs | 109 ++++++++++ .../Fields/MediaGalleryField.cs | 27 +++ .../Handlers/MediaGalleryFieldHandler.cs | 37 ++++ .../Orchard.Fields/Orchard.Fields.csproj | 20 +- .../Modules/Orchard.Fields/Placement.info | 7 + .../Settings/MediaGalleryFieldEditorEvents.cs | 35 ++++ .../Settings/MediaGalleryFieldSettings.cs | 8 + .../Styles/media-gallery-admin.css | 12 ++ .../ViewModels/MediaGalleryFieldViewModel.cs | 12 ++ .../MediaGalleryFieldSettings.cshtml | 33 +++ .../Fields/MediaGallery.Edit.cshtml | 193 ++++++++++++++++++ .../Fields/MediaGallery.SummaryAdmin.cshtml | 22 ++ .../Views/Fields/MediaGallery.cshtml | 23 +++ 13 files changed, 537 insertions(+), 1 deletion(-) create mode 100644 src/Orchard.Web/Modules/Orchard.Fields/Drivers/MediaGalleryFieldDriver.cs create mode 100644 src/Orchard.Web/Modules/Orchard.Fields/Fields/MediaGalleryField.cs create mode 100644 src/Orchard.Web/Modules/Orchard.Fields/Handlers/MediaGalleryFieldHandler.cs create mode 100644 src/Orchard.Web/Modules/Orchard.Fields/Settings/MediaGalleryFieldEditorEvents.cs create mode 100644 src/Orchard.Web/Modules/Orchard.Fields/Settings/MediaGalleryFieldSettings.cs create mode 100644 src/Orchard.Web/Modules/Orchard.Fields/Styles/media-gallery-admin.css create mode 100644 src/Orchard.Web/Modules/Orchard.Fields/ViewModels/MediaGalleryFieldViewModel.cs create mode 100644 src/Orchard.Web/Modules/Orchard.Fields/Views/DefinitionTemplates/MediaGalleryFieldSettings.cshtml create mode 100644 src/Orchard.Web/Modules/Orchard.Fields/Views/EditorTemplates/Fields/MediaGallery.Edit.cshtml create mode 100644 src/Orchard.Web/Modules/Orchard.Fields/Views/Fields/MediaGallery.SummaryAdmin.cshtml create mode 100644 src/Orchard.Web/Modules/Orchard.Fields/Views/Fields/MediaGallery.cshtml diff --git a/src/Orchard.Web/Modules/Orchard.Fields/Drivers/MediaGalleryFieldDriver.cs b/src/Orchard.Web/Modules/Orchard.Fields/Drivers/MediaGalleryFieldDriver.cs new file mode 100644 index 000000000..5ec072d9c --- /dev/null +++ b/src/Orchard.Web/Modules/Orchard.Fields/Drivers/MediaGalleryFieldDriver.cs @@ -0,0 +1,109 @@ +using System; +using Orchard.Fields.Settings; +using Orchard.ContentManagement; +using Orchard.ContentManagement.Drivers; +using Orchard.ContentManagement.Handlers; +using Orchard.Fields.Fields; +using Orchard.Fields.ViewModels; +using Orchard.Localization; +using Orchard.Services; +using Orchard.Utility.Extensions; + +namespace Orchard.Fields.Drivers { + public class MediaGalleryFieldDriver : ContentFieldDriver { + private readonly IJsonConverter _jsonConverter; + + public MediaGalleryFieldDriver(IJsonConverter jsonConverter) { + _jsonConverter = jsonConverter; + T = NullLocalizer.Instance; + } + + public Localizer T { get; set; } + + private static string GetPrefix(MediaGalleryField field, ContentPart part) { + return part.PartDefinition.Name + "." + field.Name; + } + + private static string GetDifferentiator(MediaGalleryField field, ContentPart part) { + return field.Name; + } + + protected override DriverResult Display(ContentPart part, MediaGalleryField field, string displayType, dynamic shapeHelper) { + return Combined( + ContentShape("Fields_MediaGallery", GetDifferentiator(field, part), () => shapeHelper.Fields_ContentPicker()), + ContentShape("Fields_MediaGallery_SummaryAdmin", GetDifferentiator(field, part), () => shapeHelper.Fields_MediaGallery_SummaryAdmin()) + ); + } + + protected override DriverResult Editor(ContentPart part, MediaGalleryField field, dynamic shapeHelper) { + return ContentShape("Fields_MediaGallery_Edit", GetDifferentiator(field, part), + () => { + var model = new MediaGalleryFieldViewModel { + Field = field, + Items = field.Items, + SelectedItems = field.SelectedItems + + }; + + model.SelectedItems = string.Concat(",", field.Items); + + return shapeHelper.EditorTemplate(TemplateName: "Fields/MediaGallery.Edit", Model: model, Prefix: GetPrefix(field, part)); + }); + } + + protected override DriverResult Editor(ContentPart part, MediaGalleryField field, IUpdateModel updater, dynamic shapeHelper) { + var model = new MediaGalleryFieldViewModel(); + + updater.TryUpdateModel(model, GetPrefix(field, part), null, null); + + var settings = field.PartFieldDefinition.Settings.GetModel(); + + if (String.IsNullOrEmpty(model.SelectedItems)) { + field.SelectedItems = "[]"; + } + else { + field.SelectedItems = model.SelectedItems; + } + + var allItems = _jsonConverter.Deserialize(field.SelectedItems); + + if (settings.Required && allItems.Length == 0) { + updater.AddModelError("SelectedItems", T("The field {0} is mandatory", field.Name.CamelFriendly())); + } + + if (!settings.Multiple && allItems.Length > 1) { + updater.AddModelError("SelectedItems", T("The field {0} doesn't accept multiple media items", field.Name.CamelFriendly())); + } + + return Editor(part, field, shapeHelper); + } + + //protected override void Importing(ContentPart part, Fields.MediaGalleryField field, ImportContentContext context) { + // var contentItemIds = context.Attribute(field.FieldDefinition.Name + "." + field.Name, "ContentItems"); + // if (contentItemIds != null) { + // field.Ids = contentItemIds.Split(',') + // .Select(context.GetItemFromSession) + // .Select(contentItem => contentItem.Id).ToArray(); + // } + // else { + // field.Ids = new int[0]; + // } + //} + + //protected override void Exporting(ContentPart part, Fields.MediaGalleryField field, ExportContentContext context) { + // if (field.Ids.Any()) { + // var contentItemIds = field.Ids + // .Select(x => _contentManager.Get(x)) + // .Select(x => _contentManager.GetItemMetadata(x).Identity.ToString()) + // .ToArray(); + + // context.Element(field.FieldDefinition.Name + "." + field.Name).SetAttributeValue("ContentItems", string.Join(",", contentItemIds)); + // } + //} + + protected override void Describe(DescribeMembersContext context) { + context + .Member(null, typeof(string), T("Items"), T("A Json serialized list of the media.")); + } + } +} \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Fields/Fields/MediaGalleryField.cs b/src/Orchard.Web/Modules/Orchard.Fields/Fields/MediaGalleryField.cs new file mode 100644 index 000000000..a77c940d5 --- /dev/null +++ b/src/Orchard.Web/Modules/Orchard.Fields/Fields/MediaGalleryField.cs @@ -0,0 +1,27 @@ +using System.Collections.Generic; +using Orchard.ContentManagement; +using Orchard.ContentManagement.Utilities; +using Orchard.ContentManagement.FieldStorage; + +namespace Orchard.Fields.Fields { + public class MediaGalleryField : ContentField { + internal LazyField> _mediaGalleryItems = new LazyField>(); + + public ICollection Items { get { return _mediaGalleryItems.Value ?? new MediaGalleryItem[0]; } } + + public string SelectedItems { + get { return Storage.Get(); } + set { Storage.Set(value); } + } + } + + public class MediaGalleryItem { + public string Url { get; set; } + public string AlternateText { get; set; } + public string Class { get; set; } + public string Style { get; set; } + public string Alignment { get; set; } + public int Width { get; set; } + public int Height { get; set; } + } +} diff --git a/src/Orchard.Web/Modules/Orchard.Fields/Handlers/MediaGalleryFieldHandler.cs b/src/Orchard.Web/Modules/Orchard.Fields/Handlers/MediaGalleryFieldHandler.cs new file mode 100644 index 000000000..c7b8eb72b --- /dev/null +++ b/src/Orchard.Web/Modules/Orchard.Fields/Handlers/MediaGalleryFieldHandler.cs @@ -0,0 +1,37 @@ +using System.Linq; +using Orchard.ContentManagement.Handlers; +using Orchard.ContentManagement.MetaData; +using Orchard.Fields.Fields; +using Orchard.Services; + +namespace Orchard.Fields.Handlers { + public class MediaGalleryFieldHandler : ContentHandler { + private readonly IJsonConverter _jsonConverter; + private readonly IContentDefinitionManager _contentDefinitionManager; + + public MediaGalleryFieldHandler( + IJsonConverter jsonConverter, + IContentDefinitionManager contentDefinitionManager) { + + _jsonConverter = jsonConverter; + _contentDefinitionManager = contentDefinitionManager; + } + + protected override void Loading(LoadContentContext context) { + base.Loading(context); + + var fields = context.ContentItem.Parts.SelectMany(x => x.Fields.Where(f => f.FieldDefinition.Name == typeof (MediaGalleryField).Name)).Cast(); + + // define lazy initializer for MediaGalleryField.Items + var contentTypeDefinition = _contentDefinitionManager.GetTypeDefinition(context.ContentType); + if (contentTypeDefinition == null) { + return; + } + + foreach (var field in fields) { + var localField = field; + field._mediaGalleryItems.Loader(x => _jsonConverter.Deserialize(localField.SelectedItems) ?? new MediaGalleryItem[0]); + } + } + } +} \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Fields/Orchard.Fields.csproj b/src/Orchard.Web/Modules/Orchard.Fields/Orchard.Fields.csproj index 1a2dc216e..d3c3ff544 100644 --- a/src/Orchard.Web/Modules/Orchard.Fields/Orchard.Fields.csproj +++ b/src/Orchard.Web/Modules/Orchard.Fields/Orchard.Fields.csproj @@ -72,6 +72,10 @@ + + + + @@ -114,7 +118,6 @@ - @@ -128,6 +131,8 @@ + + @@ -141,6 +146,7 @@ + @@ -160,6 +166,18 @@ + + + + + + + + + + + + 10.0 $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) diff --git a/src/Orchard.Web/Modules/Orchard.Fields/Placement.info b/src/Orchard.Web/Modules/Orchard.Fields/Placement.info index 12d0379d9..42f77fe3d 100644 --- a/src/Orchard.Web/Modules/Orchard.Fields/Placement.info +++ b/src/Orchard.Web/Modules/Orchard.Fields/Placement.info @@ -27,13 +27,20 @@ + + + + + + + diff --git a/src/Orchard.Web/Modules/Orchard.Fields/Settings/MediaGalleryFieldEditorEvents.cs b/src/Orchard.Web/Modules/Orchard.Fields/Settings/MediaGalleryFieldEditorEvents.cs new file mode 100644 index 000000000..69a5abbb9 --- /dev/null +++ b/src/Orchard.Web/Modules/Orchard.Fields/Settings/MediaGalleryFieldEditorEvents.cs @@ -0,0 +1,35 @@ +using System.Collections.Generic; +using System.Globalization; +using Orchard.ContentManagement; +using Orchard.ContentManagement.MetaData; +using Orchard.ContentManagement.MetaData.Builders; +using Orchard.ContentManagement.MetaData.Models; +using Orchard.ContentManagement.ViewModels; + +namespace Orchard.Fields.Settings { + public class MediaGalleryFieldEditorEvents : ContentDefinitionEditorEventsBase { + + public override IEnumerable PartFieldEditor(ContentPartFieldDefinition definition) { + if (definition.FieldDefinition.Name == "MediaGalleryField") { + var model = definition.Settings.GetModel(); + yield return DefinitionTemplate(model); + } + } + + public override IEnumerable PartFieldEditorUpdate(ContentPartFieldDefinitionBuilder builder, IUpdateModel updateModel) { + if (builder.FieldType != "MediaGalleryField") { + yield break; + } + + var model = new MediaGalleryFieldSettings(); + if (updateModel.TryUpdateModel(model, "MediaGalleryFieldSettings", null, null)) { + builder.WithSetting("MediaGalleryFieldSettings.Hint", model.Hint); + builder.WithSetting("MediaGalleryFieldSettings.AllowedExtensions", model.AllowedExtensions); + builder.WithSetting("MediaGalleryFieldSettings.Required", model.Required.ToString(CultureInfo.InvariantCulture)); + builder.WithSetting("MediaGalleryFieldSettings.Multiple", model.Multiple.ToString(CultureInfo.InvariantCulture)); + } + + yield return DefinitionTemplate(model); + } + } +} \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Fields/Settings/MediaGalleryFieldSettings.cs b/src/Orchard.Web/Modules/Orchard.Fields/Settings/MediaGalleryFieldSettings.cs new file mode 100644 index 000000000..e64138143 --- /dev/null +++ b/src/Orchard.Web/Modules/Orchard.Fields/Settings/MediaGalleryFieldSettings.cs @@ -0,0 +1,8 @@ +namespace Orchard.Fields.Settings { + public class MediaGalleryFieldSettings { + public string Hint { get; set; } + public string AllowedExtensions { get; set; } + public bool Required { get; set; } + public bool Multiple { get; set; } + } +} diff --git a/src/Orchard.Web/Modules/Orchard.Fields/Styles/media-gallery-admin.css b/src/Orchard.Web/Modules/Orchard.Fields/Styles/media-gallery-admin.css new file mode 100644 index 000000000..e55221a3b --- /dev/null +++ b/src/Orchard.Web/Modules/Orchard.Fields/Styles/media-gallery-admin.css @@ -0,0 +1,12 @@ +table.media-gallery tr td:nth-child(1) { + background: url(images/move.gif) no-repeat 12px 14px; + cursor: move; +} + +.media-gallery-message { + display: none; +} + +.ui-sortable-helper .media-gallery-remove { + display: none; +} \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Fields/ViewModels/MediaGalleryFieldViewModel.cs b/src/Orchard.Web/Modules/Orchard.Fields/ViewModels/MediaGalleryFieldViewModel.cs new file mode 100644 index 000000000..a841ae77b --- /dev/null +++ b/src/Orchard.Web/Modules/Orchard.Fields/ViewModels/MediaGalleryFieldViewModel.cs @@ -0,0 +1,12 @@ +using System.Collections.Generic; +using Orchard.Fields.Fields; + +namespace Orchard.Fields.ViewModels { + + public class MediaGalleryFieldViewModel { + + public ICollection Items { get; set; } + public string SelectedItems { get; set; } + public MediaGalleryField Field { get; set; } + } +} \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Fields/Views/DefinitionTemplates/MediaGalleryFieldSettings.cshtml b/src/Orchard.Web/Modules/Orchard.Fields/Views/DefinitionTemplates/MediaGalleryFieldSettings.cshtml new file mode 100644 index 000000000..2f1e70c73 --- /dev/null +++ b/src/Orchard.Web/Modules/Orchard.Fields/Views/DefinitionTemplates/MediaGalleryFieldSettings.cshtml @@ -0,0 +1,33 @@ +@model Orchard.Fields.Settings.MediaGalleryFieldSettings + +
+
+ @Html.CheckBoxFor(m => m.Required) + @T("Check to ensure the user is providing at least one media.") +
+
+
+
+ checked="checked" } /> + +
+
+
+ @Html.TextBoxFor(m => m.AllowedExtensions, new { @class = "textMedium" }) + @T("You can define a set of extensions the user will be able to pick, separated by spaces, e.g. jpg png gif") + @T("Leave it empty if you don't want to apply any restriction.") +
+
+
+
+
+ @Html.CheckBoxFor(m => m.Multiple) + @T("Check to allow the user to select multiple media items.") +
+
+
+ + @Html.TextAreaFor(m => m.Hint, new { @class = "textMedium", rows = "5" } ) + @T("The help text is written under the field when authors are selecting media items.") + @Html.ValidationMessageFor(m => m.Hint) +
diff --git a/src/Orchard.Web/Modules/Orchard.Fields/Views/EditorTemplates/Fields/MediaGallery.Edit.cshtml b/src/Orchard.Web/Modules/Orchard.Fields/Views/EditorTemplates/Fields/MediaGallery.Edit.cshtml new file mode 100644 index 000000000..85897fb85 --- /dev/null +++ b/src/Orchard.Web/Modules/Orchard.Fields/Views/EditorTemplates/Fields/MediaGallery.Edit.cshtml @@ -0,0 +1,193 @@ +@model MediaGalleryFieldViewModel +@using Orchard.Fields.Settings; + +@{ + Style.Include("media-gallery-admin"); + Script.Require("jQueryUI_Sortable").AtFoot(); + + var settings = Model.Field.PartFieldDefinition.Settings.GetModel(); + var descriminator = Html.FieldIdFor(m => m.Field.Items); +} + +
+ + @settings.Hint + + + + + + + + + + + + + + + + + @foreach (var media in Model.Items) { + + + + + + } + + + + @T("Add") + + @Html.HiddenFor(m => m.SelectedItems) +
+ +@using (Script.Foot()) { + +} \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Fields/Views/Fields/MediaGallery.SummaryAdmin.cshtml b/src/Orchard.Web/Modules/Orchard.Fields/Views/Fields/MediaGallery.SummaryAdmin.cshtml new file mode 100644 index 000000000..d54c06633 --- /dev/null +++ b/src/Orchard.Web/Modules/Orchard.Fields/Views/Fields/MediaGallery.SummaryAdmin.cshtml @@ -0,0 +1,22 @@ +@using Orchard.Utility.Extensions; + +@{ + var field = (MediaGalleryField) Model.ContentField; + string name = field.DisplayName; + var items = field.Items; +} + + diff --git a/src/Orchard.Web/Modules/Orchard.Fields/Views/Fields/MediaGallery.cshtml b/src/Orchard.Web/Modules/Orchard.Fields/Views/Fields/MediaGallery.cshtml new file mode 100644 index 000000000..06d85bfc6 --- /dev/null +++ b/src/Orchard.Web/Modules/Orchard.Fields/Views/Fields/MediaGallery.cshtml @@ -0,0 +1,23 @@ +@using Orchard.Fields.Fields +@using Orchard.Utility.Extensions; + +@{ + var field = (MediaGalleryField) Model.ContentField; + string name = field.DisplayName; + var contentItems = field.ContentItems; +} +

+ @name: + @if(contentItems.Any()) { + foreach(var contentItem in contentItems) { + @Html.ItemDisplayLink(contentItem) + if(contentItem != contentItems.Last()) { + , + } + } + } + else { + @T("No content items.") + } +

+