-
Notifications
You must be signed in to change notification settings - Fork 1.4k
Implements ContentPicker localization options discussed in #7352 #7391
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
sebastienros
merged 6 commits into
OrchardCMS:1.10.x
from
LaserSrl:issue/7352_ContentPickerLocalizationUpgrades_ExtensionFeature
Nov 17, 2016
Merged
Changes from 1 commit
Commits
Show all changes
6 commits
Select commit
Hold shift + click to select a range
6efa830
Squashed commit of the following:
MatteoPiovanelli 417c63b
Changed the view as reccomended by @sebastienros in his comments
MatteoPiovanelli eb9d256
Added culture information to the contentpickerfield editor view
MatteoPiovanelli ab9eb4e
Fixed a bug in the handler (!= instead of ==)
MatteoPiovanelli 0673617
showing displaytext in warnings and notifications rather than content…
MatteoPiovanelli 4287696
Cleanup. I
MatteoPiovanelli File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
39 changes: 39 additions & 0 deletions
39
...Orchard.Web/Modules/Orchard.ContentPicker/Drivers/ContentPickerFieldLocalizationDriver.cs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,39 @@ | ||
| using System.Linq; | ||
| using Orchard.ContentManagement; | ||
| using Orchard.ContentManagement.Drivers; | ||
| using Orchard.ContentPicker.ViewModels; | ||
| using Orchard.Environment.Extensions; | ||
|
|
||
| namespace Orchard.ContentPicker.Drivers { | ||
| [OrchardFeature("Orchard.ContentPicker.LocalizationExtensions")] | ||
| public class ContentPickerFieldLocalizationDriver : ContentFieldDriver<Fields.ContentPickerField> { | ||
| private readonly IContentManager _contentManager; | ||
|
|
||
| public ContentPickerFieldLocalizationDriver(IContentManager contentManager) { | ||
| _contentManager = contentManager; | ||
| } | ||
|
|
||
| private static string GetPrefix(Fields.ContentPickerField field, ContentPart part) { | ||
| return part.PartDefinition.Name + "." + field.Name; | ||
| } | ||
|
|
||
| private static string GetDifferentiator(Fields.ContentPickerField field, ContentPart part) { | ||
| return field.Name; | ||
| } | ||
|
|
||
| protected override DriverResult Editor(ContentPart part, Fields.ContentPickerField field, dynamic shapeHelper) { | ||
| return ContentShape("Fields_ContentPickerLocalization_Edit", GetDifferentiator(field, part), | ||
| () => { | ||
| var model = new ContentPickerFieldViewModel { | ||
| Field = field, | ||
| Part = part, | ||
| ContentItems = _contentManager.GetMany<ContentItem>(field.Ids, VersionOptions.Latest, QueryHints.Empty).ToList() | ||
| }; | ||
|
|
||
| model.SelectedIds = string.Join(",", field.Ids); | ||
|
|
||
| return shapeHelper.EditorTemplate(TemplateName: "Fields/ContentPickerLocalization.Edit", Model: model, Prefix: GetPrefix(field, part)); | ||
| }); | ||
| } | ||
| } | ||
| } |
112 changes: 112 additions & 0 deletions
112
.../Modules/Orchard.ContentPicker/Handlers/ContentPickerFieldLocalizationExtensionHandler.cs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,112 @@ | ||
| using System; | ||
| using System.Collections.Generic; | ||
| using System.Linq; | ||
| using Orchard.ContentManagement; | ||
| using Orchard.ContentManagement.Handlers; | ||
| using Orchard.ContentPicker.Fields; | ||
| using Orchard.ContentPicker.Settings; | ||
| using Orchard.Environment.Extensions; | ||
| using Orchard.Localization; | ||
| using Orchard.Localization.Models; | ||
| using Orchard.Localization.Services; | ||
| using Orchard.UI.Notify; | ||
|
|
||
| namespace Orchard.ContentPicker.Handlers { | ||
| [OrchardFeature("Orchard.ContentPicker.LocalizationExtensions")] | ||
| public class ContentPickerFieldLocalizationExtensionHandler : ContentHandler { | ||
| private readonly IOrchardServices _orchardServices; | ||
| private readonly IContentManager _contentManager; | ||
| private readonly ILocalizationService _localizationService; | ||
| public Localizer T { get; set; } | ||
|
|
||
| public ContentPickerFieldLocalizationExtensionHandler( | ||
| IOrchardServices orchardServices, | ||
| IContentManager contentManager, | ||
| ILocalizationService localizationService) { | ||
| _orchardServices = orchardServices; | ||
| _contentManager = contentManager; | ||
| _localizationService = localizationService; | ||
|
|
||
| T = NullLocalizer.Instance; | ||
| } | ||
|
|
||
| protected override void UpdateEditorShape(UpdateEditorContext context) { | ||
| base.UpdateEditorShape(context); | ||
| //Here we implement the logic based on the settings introduced in ContentPickerFieldLocalizationSettings | ||
| //These settings should only be active if the ContentItem that is being updated has a LocalizationPart | ||
| if (context.ContentItem.Parts.Any(part => part is LocalizationPart)) { | ||
| var lPart = (LocalizationPart)context.ContentItem.Parts.Single(part => part is LocalizationPart); | ||
| var fields = context.ContentItem.Parts.SelectMany(x => x.Fields.Where(f => f.FieldDefinition.Name == typeof(ContentPickerField).Name)).Cast<ContentPickerField>(); | ||
|
|
||
| foreach (var field in fields) { | ||
| var settings = field.PartFieldDefinition.Settings.GetModel<ContentPickerFieldLocalizationSettings>(); | ||
| if (settings.TryToLocalizeItems) { | ||
| //try to replace items in the field with their translation | ||
| var itemsInField = _contentManager.GetMany<ContentItem>(field.Ids, VersionOptions.Published, QueryHints.Empty); | ||
| if (settings.RemoveItemsWithNoLocalizationPart && itemsInField.Where(ci => !ci.Parts.Any(part => part is LocalizationPart)).Any()) { | ||
| //keep only items that have a LocalizationPart | ||
| _orchardServices.Notifier.Warning(T( | ||
| "{0}: The following items could have no localization, so they were removed: {1}", | ||
| field.DisplayName, | ||
| string.Join(", ", itemsInField.Where(ci => !ci.Parts.Any(part => part is LocalizationPart)).Select(ci => ci.Id.ToString())) | ||
| )); | ||
| itemsInField = itemsInField.Where(ci => ci.Parts.Any(part => part is LocalizationPart)); | ||
| } | ||
| //use an (int, int) tuple to track translations | ||
| var newIds = itemsInField.Select(ci => { | ||
| if (ci.Parts.Any(part => part is LocalizationPart)) { | ||
| if (_localizationService.GetContentCulture(ci) == lPart.Culture.Culture) | ||
| return new Tuple<int, int>(ci.Id, ci.Id); //this item is fine | ||
| var localized = _localizationService.GetLocalizations(ci).FirstOrDefault(lp => lp.Culture == lPart.Culture); | ||
| return localized == null ? new Tuple<int, int>(ci.Id, -ci.Id) : new Tuple<int, int>(ci.Id, localized.Id); //return negative id where we found no translation | ||
| } | ||
| else { | ||
| //we only go here if RemoveItemsWithNoLocalizationPart == false | ||
| return new Tuple<int, int>(ci.Id, ci.Id); | ||
| } | ||
| }); | ||
| if (settings.RemoveItemsWithoutLocalization) { | ||
| //remove the items for which we could not find a localization | ||
| _orchardServices.Notifier.Warning(T( | ||
| "{0}: We could not find a localization for the following items, so they were removed: {1}", | ||
| field.DisplayName, | ||
| string.Join(", ", newIds.Where(tup => tup.Item2 < 0).Select(tup => tup.Item1.ToString())) | ||
| )); | ||
| newIds = newIds.Where(tup => tup.Item2 > 0); | ||
| } | ||
| else { | ||
| //negative Ids are made positive again | ||
| newIds = newIds.Select(tup => tup = new Tuple<int, int>(tup.Item1, Math.Abs(tup.Item2))); | ||
| } | ||
| if (newIds.Where(tup => tup.Item1 != tup.Item2).Any()) { | ||
| _orchardServices.Notifier.Warning(T( | ||
| "{0}: The following items were replaced by their correct localization: {1}", | ||
| field.DisplayName, | ||
| string.Join(", ", newIds.Where(tup => tup.Item1 != tup.Item2).Select(tup => tup.Item1.ToString())) | ||
| )); | ||
| } | ||
|
|
||
| field.Ids = newIds.Select(tup => tup.Item2).Distinct().ToArray(); | ||
| } | ||
| if (settings.AssertItemsHaveSameCulture) { | ||
| //verify that the items in the ContentPickerField are all in the culture of the ContentItem whose editor we are updating | ||
| var itemsInField = _contentManager.GetMany<ContentItem>(field.Ids, VersionOptions.Published, QueryHints.Empty); | ||
| var itemsWithoutLocalizationPart = itemsInField.Where(ci => !ci.Parts.Any(part => part is LocalizationPart)); | ||
| List<int> badItemIds = itemsInField.Where(ci => ci.Parts.Any(part => part is LocalizationPart && ((LocalizationPart)part).Culture == lPart.Culture)).Select(ci => ci.Id).ToList(); | ||
| if (itemsWithoutLocalizationPart.Count() > 0) { | ||
| //Verify items from the ContentPickerField that cannot be localized | ||
| _orchardServices.Notifier.Warning(T("{0}: Some of the selected items cannot be localized. Ids: {1}", field.DisplayName, string.Join(", ", itemsWithoutLocalizationPart.Select(ci => ci.Id)))); | ||
| if (settings.BlockForItemsWithNoLocalizationPart) { | ||
| badItemIds.AddRange(itemsWithoutLocalizationPart.Select(ci => ci.Id)); | ||
| } | ||
| } | ||
| if (badItemIds.Count > 0) { | ||
| context.Updater.AddModelError(field.DisplayName, T("Some of the items selected have the wrong localization. Ids: {0}", string.Join(", ", badItemIds.Select(id => id.ToString())))); | ||
| } | ||
| } | ||
| } | ||
| } | ||
| } | ||
|
|
||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
38 changes: 38 additions & 0 deletions
38
....Web/Modules/Orchard.ContentPicker/Settings/ContentPickerFieldLocalizationEditorEvents.cs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,38 @@ | ||
| 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; | ||
| using Orchard.Environment.Extensions; | ||
|
|
||
| namespace Orchard.ContentPicker.Settings { | ||
| [OrchardFeature("Orchard.ContentPicker.LocalizationExtensions")] | ||
| public class ContentPickerFieldLocalizationEditorEvents : ContentDefinitionEditorEventsBase { | ||
|
|
||
| public override IEnumerable<TemplateViewModel> PartFieldEditor(ContentPartFieldDefinition definition) { | ||
| if (definition.FieldDefinition.Name == "ContentPickerField") { | ||
| var model = definition.Settings.GetModel<ContentPickerFieldLocalizationSettings>(); | ||
| yield return DefinitionTemplate(model); | ||
| } | ||
| } | ||
|
|
||
| public override IEnumerable<TemplateViewModel> PartFieldEditorUpdate(ContentPartFieldDefinitionBuilder builder, IUpdateModel updateModel) { | ||
| if (builder.FieldType != "ContentPickerField") { | ||
| yield break; | ||
| } | ||
|
|
||
| var model = new ContentPickerFieldLocalizationSettings(); | ||
| if (updateModel.TryUpdateModel(model, "ContentPickerFieldLocalizationSettings", null, null)) { | ||
| builder.WithSetting("ContentPickerFieldLocalizationSettings.TryToLocalizeItems", model.TryToLocalizeItems.ToString(CultureInfo.InvariantCulture)); | ||
| builder.WithSetting("ContentPickerFieldLocalizationSettings.RemoveItemsWithoutLocalization", model.RemoveItemsWithoutLocalization.ToString(CultureInfo.InvariantCulture)); | ||
| builder.WithSetting("ContentPickerFieldLocalizationSettings.RemoveItemsWithNoLocalizationPart", model.RemoveItemsWithNoLocalizationPart.ToString(CultureInfo.InvariantCulture)); | ||
| builder.WithSetting("ContentPickerFieldLocalizationSettings.AssertItemsHaveSameCulture", model.AssertItemsHaveSameCulture.ToString(CultureInfo.InvariantCulture)); | ||
| builder.WithSetting("ContentPickerFieldLocalizationSettings.BlockForItemsWithNoLocalizationPart", model.BlockForItemsWithNoLocalizationPart.ToString(CultureInfo.InvariantCulture)); | ||
| } | ||
|
|
||
| yield return DefinitionTemplate(model); | ||
| } | ||
| } | ||
| } |
16 changes: 16 additions & 0 deletions
16
...hard.Web/Modules/Orchard.ContentPicker/Settings/ContentPickerFieldLocalizationSettings.cs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,16 @@ | ||
| using Orchard.Environment.Extensions; | ||
|
|
||
| namespace Orchard.ContentPicker.Settings { | ||
| [OrchardFeature("Orchard.ContentPicker.LocalizationExtensions")] | ||
| public class ContentPickerFieldLocalizationSettings { | ||
|
|
||
| public ContentPickerFieldLocalizationSettings() { | ||
| TryToLocalizeItems = true; | ||
| } | ||
| public bool TryToLocalizeItems { get; set; } | ||
| public bool RemoveItemsWithoutLocalization { get; set; } | ||
| public bool RemoveItemsWithNoLocalizationPart { get; set; } | ||
| public bool AssertItemsHaveSameCulture { get; set; } | ||
| public bool BlockForItemsWithNoLocalizationPart { get; set; } | ||
| } | ||
| } |
54 changes: 54 additions & 0 deletions
54
...ard.ContentPicker/Views/DefinitionTemplates/ContentPickerFieldLocalizationSettings.cshtml
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,54 @@ | ||
| @model Orchard.ContentPicker.Settings.ContentPickerFieldLocalizationSettings | ||
|
|
||
| <fieldset> | ||
| @Html.CheckBoxFor(m => m.TryToLocalizeItems) | ||
| <label for="@Html.FieldIdFor(m => m.TryToLocalizeItems)" class="forcheckbox">@T("Try to replace selected items with their correct localization.")</label> | ||
| <span class="hint">@T("Check to attempt to replace items selected in this field with their translation in the main ContentItem's culture. This only applies if the main ContentItem has a LocalizationPart.")</span> | ||
| <div id="@Html.FieldIdFor(m => m)_subOption1" style="display:none; padding-left:2em;"> | ||
| @Html.CheckBoxFor(m => m.RemoveItemsWithoutLocalization) | ||
| <label for="@Html.FieldIdFor(m => m.RemoveItemsWithoutLocalization)" class="forcheckbox">@T("Remove items that do not have the correct translation.")</label> | ||
| <span class="hint">@T("Check to remove items from the ContentPickerField when the items selected do not have a version in the correct culture (they have a LocalizationPart, but not a translation in the main ContentItem's culture').")</span> | ||
| @Html.CheckBoxFor(m => m.RemoveItemsWithNoLocalizationPart) | ||
| <label for="@Html.FieldIdFor(m => m.RemoveItemsWithNoLocalizationPart)" class="forcheckbox">@T("Remove items that cannot be localized.")</label> | ||
| <span class="hint">@T("Check to remove items from the ContentPickerField when the items selected cannot be localized (do not have a LocalizationPart).")</span> | ||
| </div> | ||
|
|
||
| @Html.CheckBoxFor(m => m.AssertItemsHaveSameCulture) | ||
| <label for="@Html.FieldIdFor(m => m.AssertItemsHaveSameCulture)" class="forcheckbox">@T("Verify culture of selected items.")</label> | ||
| <span class="hint">@T("Check to prevent publication of contents when the items selected have a different culture. This only applies if the main ContentItem has a LocalizationPart.")</span> | ||
| <div id="@Html.FieldIdFor(m => m)_subOption2" style="display:none; padding-left:2em;"> | ||
| @Html.CheckBoxFor(m => m.BlockForItemsWithNoLocalizationPart) | ||
| <label for="@Html.FieldIdFor(m => m.BlockForItemsWithNoLocalizationPart)" class="forcheckbox">@T("Do not admit items that cannot be localized.")</label> | ||
| <span class="hint">@T("Check to stop publication of contents when the items selected cannot be localized (do not have a LocalizationPart).")</span> | ||
| </div> | ||
| </fieldset> | ||
|
|
||
| @using (Script.Foot()) { | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Look into the Users settings.
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Specifically the |
||
| Script.Require("jQuery"); | ||
| <script type="text/javascript"> | ||
| function ShowHideSubOption1() { | ||
| var assertOption = $('#@Html.FieldIdFor(m => m.TryToLocalizeItems)').is(':checked'); | ||
| if (assertOption === true) { | ||
| $('#@Html.FieldIdFor(m => m)_subOption1').show(400); | ||
| } else { | ||
| $('#@Html.FieldIdFor(m => m)_subOption1').hide(400); | ||
| } | ||
| } | ||
| function ShowHideSubOption2() { | ||
| var assertOption = $('#@Html.FieldIdFor(m => m.AssertItemsHaveSameCulture)').is(':checked'); | ||
| if (assertOption === true) { | ||
| $('#@Html.FieldIdFor(m => m)_subOption2').show(400); | ||
| } else { | ||
| $('#@Html.FieldIdFor(m => m)_subOption2').hide(400); | ||
| } | ||
| } | ||
| $(function () { | ||
| //the checkboxes have been "populated" already, so we can check their values | ||
| ShowHideSubOption1(); | ||
| ShowHideSubOption2(); | ||
|
|
||
| $('#@Html.FieldIdFor(m => m.TryToLocalizeItems)').change(ShowHideSubOption1); | ||
| $('#@Html.FieldIdFor(m => m.AssertItemsHaveSameCulture)').change(ShowHideSubOption2); | ||
| }); | ||
| </script> | ||
| } | ||
27 changes: 27 additions & 0 deletions
27
.../Orchard.ContentPicker/Views/EditorTemplates/Fields/ContentPickerLocalization.Edit.cshtml
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,27 @@ | ||
| @model Orchard.ContentPicker.ViewModels.ContentPickerFieldViewModel | ||
| @using Orchard.ContentPicker.Settings; | ||
|
|
||
| @{ | ||
| Script.Require("jQuery").AtFoot(); | ||
|
|
||
| var settings = Model.Field.PartFieldDefinition.Settings.GetModel<ContentPickerFieldLocalizationSettings>(); | ||
|
|
||
| string tryTranslateMsg = T("Selected items with a localization different than the current one will be localized.").Text; | ||
| string removeMissingMsg = T("Selected items for which there is no correct localization will be removed.").Text; | ||
| string removeUnlocalizableMsg = T("Selected items that cannot have localizations will be removed.").Text; | ||
|
|
||
| if (settings.RemoveItemsWithoutLocalization) { tryTranslateMsg += " " + removeMissingMsg; } | ||
| if (settings.RemoveItemsWithNoLocalizationPart) { tryTranslateMsg += " " + removeUnlocalizableMsg; } | ||
|
|
||
| //We will use a script to find the fieldset for the field we are currently processing. | ||
| //The fieldset contains a span of class "hint". We will add tryTranslateMsg to it. | ||
| string dataPartName = HttpUtility.JavaScriptStringEncode(Model.Part.PartDefinition.Name); | ||
| string dataFieldName = HttpUtility.JavaScriptStringEncode(Model.Field.PartFieldDefinition.Name); | ||
| } | ||
| @using (Script.Foot()) { | ||
| <script type="text/javascript"> | ||
| $(function () { | ||
| $("fieldset[data-part-name='@dataPartName'][data-field-name='@dataFieldName']").find("span.hint")[0].innerText += "@tryTranslateMsg"; | ||
| }); | ||
| </script> | ||
| } |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please remove any inline style. Or prove that it would be too ugly otherwise.