Projection default settings (#8497)

* added settings in projection part
* read settings into driver
* commit files setting
* add logic of filter query
* added logic of filter query setting
* managed import/export
* fixed migration
* added message information
Co-authored-by: elena.lampugnani <elena.lampugnani@laser-group.com>
This commit is contained in:
Hermes Sbicego
2021-09-03 09:03:27 +02:00
committed by GitHub
parent b00678abf4
commit 4e69612d90
10 changed files with 673 additions and 84 deletions

View File

@@ -16,6 +16,7 @@ using Orchard.Projections.Descriptors.Layout;
using Orchard.Projections.Descriptors.Property;
using Orchard.Projections.Models;
using Orchard.Projections.Services;
using Orchard.Projections.Settings;
using Orchard.Projections.ViewModels;
using Orchard.Tokens;
using Orchard.UI.Navigation;
@@ -59,7 +60,7 @@ namespace Orchard.Projections.Drivers {
// retrieving paging parameters
var queryString = Services.WorkContext.HttpContext.Request.QueryString;
var pageKey = String.IsNullOrWhiteSpace(part.Record.PagerSuffix) ? "page" : "page-" + part.Record.PagerSuffix;
var page = 0;
@@ -97,7 +98,7 @@ namespace Orchard.Projections.Drivers {
return Combined(
ContentShape("Parts_ProjectionPart_Pager", shape => {
if(!part.Record.DisplayPager) {
if (!part.Record.DisplayPager) {
return null;
}
@@ -189,7 +190,7 @@ namespace Orchard.Projections.Drivers {
var groups = layoutComponents.GroupBy(
x => {
var propertyShape = ((IEnumerable<dynamic>)x.Properties.Items).First(p => ((PropertyRecord)p.Property).Id == groupPropertyId);
// clear the wrappers, as they shouldn't be needed to generate the grouping key itself
// otherwise the DisplayContext.View is null, and throws an exception if a wrapper is rendered (#18558)
((IShape)propertyShape).Metadata.Wrappers.Clear();
@@ -224,41 +225,76 @@ namespace Orchard.Projections.Drivers {
protected override DriverResult Editor(ProjectionPart part, dynamic shapeHelper) {
return ContentShape("Parts_ProjectionPart_Edit",
() => {
var model = new ProjectionPartEditViewModel();
var model = new ProjectionPartEditViewModel {
DisplayPager = part.Record.DisplayPager,
Items = part.Record.Items,
ItemsPerPage = part.Record.ItemsPerPage,
Skip = part.Record.Skip,
PagerSuffix = part.Record.PagerSuffix,
MaxItems = part.Record.MaxItems,
QueryLayoutRecordId = "-1",
};
// concatenated Query and Layout ids for the view
if (part.Record.QueryPartRecord != null) {
model.QueryLayoutRecordId = part.Record.QueryPartRecord.Id + ";";
}
if (part.Record.LayoutRecord != null) {
model.QueryLayoutRecordId += part.Record.LayoutRecord.Id.ToString();
// for create read the setting values
var settings = part.TypePartDefinition.Settings.GetModel<ProjectionPartSettings>();
if (part.Id == 0) {
model = new ProjectionPartEditViewModel {
DisplayPager = settings.DisplayPager,
Items = settings.Items,
Skip = settings.Skip,
PagerSuffix = settings.PagerSuffix,
MaxItems = settings.MaxItems,
QueryLayoutRecordId = settings.QueryLayoutRecordId
};
}
else {
model.QueryLayoutRecordId += "-1";
model = new ProjectionPartEditViewModel {
DisplayPager = part.Record.DisplayPager,
Items = part.Record.Items,
ItemsPerPage = part.Record.ItemsPerPage,
Skip = part.Record.Skip,
PagerSuffix = part.Record.PagerSuffix,
MaxItems = part.Record.MaxItems,
QueryLayoutRecordId = "-1"
};
// concatenated Query and Layout ids for the view
if (part.Record.QueryPartRecord != null) {
model.QueryLayoutRecordId = part.Record.QueryPartRecord.Id + ";";
}
if (part.Record.LayoutRecord != null) {
model.QueryLayoutRecordId += part.Record.LayoutRecord.Id.ToString();
}
else {
model.QueryLayoutRecordId += "-1";
}
}
model.PartId = part.Id;
// lock fields
model.LockEditingItems = settings.LockEditingItems;
model.LockEditingSkip = settings.LockEditingSkip;
model.LockEditingMaxItems = settings.LockEditingMaxItems;
model.LockEditingPagerSuffix = settings.LockEditingPagerSuffix;
model.LockEditingDisplayPager = settings.LockEditingDisplayPager;
// populating the list of queries and layouts
var layouts = _projectionManager.DescribeLayouts().SelectMany(x => x.Descriptors).ToList();
model.QueryRecordEntries = Services.ContentManager.Query<QueryPart, QueryPartRecord>().Join<TitlePartRecord>().OrderBy(x => x.Title).List()
.Select(x => new QueryRecordEntry {
Id = x.Id,
Name = x.Name,
LayoutRecordEntries = x.Layouts.Select( l => new LayoutRecordEntry {
Id = l.Id,
Description = GetLayoutDescription(layouts, l)
})
});
.Select(x => new QueryRecordEntry {
Id = x.Id,
Name = x.Name,
LayoutRecordEntries = x.Layouts.Select(l => new LayoutRecordEntry {
Id = l.Id,
Description = GetLayoutDescription(layouts, l)
})
});
// if any values, use default list of the settings
if (!string.IsNullOrWhiteSpace(settings.FilterQueryRecordId)) {
var filterQueryRecordId = settings.FilterQueryRecordId.Split('&');
model.QueryRecordIdFilterEntries = filterQueryRecordId
.Select(x => new QueryRecordFilterEntry {
Id = x.Split(';')[0],
LayoutId = x.Split(';')[1]
});
}
else {
model.QueryRecordIdFilterEntries = new List<QueryRecordFilterEntry>();
}
return shapeHelper.EditorTemplate(TemplateName: TemplateName, Model: model, Prefix: Prefix);
});
@@ -266,28 +302,58 @@ namespace Orchard.Projections.Drivers {
private static string GetLayoutDescription(IEnumerable<LayoutDescriptor> layouts, LayoutRecord l) {
var descriptor = layouts.FirstOrDefault(x => l.Category == x.Category && l.Type == x.Type);
return String.IsNullOrWhiteSpace(l.Description) ? descriptor.Display(new LayoutContext {State = FormParametersHelper.ToDynamic(l.State)}).Text : l.Description;
return String.IsNullOrWhiteSpace(l.Description) ? descriptor.Display(new LayoutContext { State = FormParametersHelper.ToDynamic(l.State) }).Text : l.Description;
}
protected override DriverResult Editor(ProjectionPart part, IUpdateModel updater, dynamic shapeHelper) {
var settings = part.TypePartDefinition.Settings.GetModel<ProjectionPartSettings>();
var model = new ProjectionPartEditViewModel();
if (updater.TryUpdateModel(model, Prefix, null, null)) {
var queryLayoutIds = model.QueryLayoutRecordId.Split(new[] {';'});
updater.TryUpdateModel(model, Prefix, null, null);
model.PartId = part.Id;
// check the setting, if it is unlocked, assign the setting value
if (settings.LockEditingDisplayPager) {
part.Record.DisplayPager = settings.DisplayPager;
}
else {
part.Record.DisplayPager = model.DisplayPager;
}
if (settings.LockEditingItems) {
part.Record.Items = settings.Items;
}
else {
part.Record.Items = model.Items;
part.Record.ItemsPerPage = model.ItemsPerPage;
}
part.Record.ItemsPerPage = model.ItemsPerPage;
if (settings.LockEditingSkip) {
part.Record.Skip = settings.Skip;
}
else {
part.Record.Skip = model.Skip;
}
if (settings.LockEditingMaxItems) {
part.Record.MaxItems = settings.MaxItems;
}
else {
part.Record.MaxItems = model.MaxItems;
}
if (settings.LockEditingPagerSuffix) {
part.Record.PagerSuffix = (settings.PagerSuffix ?? String.Empty).Trim();
}
else {
part.Record.PagerSuffix = (model.PagerSuffix ?? String.Empty).Trim();
part.Record.QueryPartRecord = _queryRepository.Get(Int32.Parse(queryLayoutIds[0]));
part.Record.LayoutRecord = part.Record.QueryPartRecord.Layouts.FirstOrDefault(x => x.Id == Int32.Parse(queryLayoutIds[1]));
}
if(!String.IsNullOrWhiteSpace(part.Record.PagerSuffix) && !String.Equals(part.Record.PagerSuffix.ToSafeName(), part.Record.PagerSuffix, StringComparison.OrdinalIgnoreCase)) {
updater.AddModelError("PagerSuffix", T("Suffix should not contain special characters."));
}
var queryLayoutIds = model.QueryLayoutRecordId.Split(new[] { ';' });
part.Record.QueryPartRecord = _queryRepository.Get(Int32.Parse(queryLayoutIds[0]));
part.Record.LayoutRecord = part.Record.QueryPartRecord.Layouts.FirstOrDefault(x => x.Id == Int32.Parse(queryLayoutIds[1]));
if (!String.IsNullOrWhiteSpace(part.Record.PagerSuffix) && !String.Equals(part.Record.PagerSuffix.ToSafeName(), part.Record.PagerSuffix, StringComparison.OrdinalIgnoreCase)) {
updater.AddModelError("PagerSuffix", T("Suffix should not contain special characters."));
}
return Editor(part, shapeHelper);
@@ -310,7 +376,7 @@ namespace Orchard.Projections.Drivers {
protected override void ImportCompleted(ProjectionPart part, ImportContentContext context) {
// Assign the query only when everything is imported.
var query = context.Attribute(part.PartDefinition.Name, "Query");
if (query != null) {
if (query != null && context.GetItemFromSession(query).As<QueryPart>()!=null) {
part.Record.QueryPartRecord = context.GetItemFromSession(query).As<QueryPart>().Record;
var layoutIndex = context.Attribute(part.PartDefinition.Name, "LayoutIndex");
int layoutIndexValue;
@@ -346,3 +412,4 @@ namespace Orchard.Projections.Drivers {
}
}
}

View File

@@ -105,6 +105,7 @@ namespace Orchard.Projections.Drivers {
new XAttribute("Display", layout.Display),
new XAttribute("DisplayType", layout.DisplayType ?? ""),
new XAttribute("Type", layout.Type ?? ""),
new XAttribute("GUIdentifier", layout.GUIdentifier ?? ""),
// Properties
new XElement("Properties", layout.Properties.Select(GetPropertyXml)),
@@ -194,6 +195,7 @@ namespace Orchard.Projections.Drivers {
DisplayType = layout.Attribute("DisplayType").Value,
State = state,
Type = type,
GUIdentifier = string.IsNullOrWhiteSpace(layout.Attribute("GUIdentifier").Value) ? Guid.NewGuid().ToString() : layout.Attribute("GUIdentifier").Value,
Properties = layout.Element("Properties").Elements("Property").Select(GetProperty).ToList(),
GroupProperty = GetProperty(layout.Element("Group").Element("Property"))
};

View File

@@ -1,4 +1,7 @@
using System.Data;
using System;
using System.Data;
using System.Linq;
using Orchard.ContentManagement;
using Orchard.ContentManagement.MetaData;
using Orchard.Core.Common.Models;
using Orchard.Core.Contents.Extensions;
@@ -11,9 +14,14 @@ using Orchard.Projections.Models;
namespace Orchard.Projections {
public class Migrations : DataMigrationImpl {
private readonly IRepository<MemberBindingRecord> _memberBindingRepository;
private readonly IRepository<LayoutRecord> _layoutRepository;
public Migrations(IRepository<MemberBindingRecord> memberBindingRepository) {
public Migrations(
IRepository<MemberBindingRecord> memberBindingRepository,
IRepository<LayoutRecord> layoutRepository) {
_memberBindingRepository = memberBindingRepository;
_layoutRepository = layoutRepository;
T = NullLocalizer.Instance;
}
@@ -311,5 +319,17 @@ namespace Orchard.Projections {
.AddColumn<string>("VersionScope", c => c.WithLength(15)));
return 5;
}
public int UpdateFrom5() {
SchemaBuilder.AlterTable("LayoutRecord", t => t.AddColumn<string>("GUIdentifier",
column => column.WithLength(68)));
var layoutRecords = _layoutRepository.Table.Where(l => l.GUIdentifier == null || l.GUIdentifier == "").ToList();
foreach (var layout in layoutRecords) {
layout.GUIdentifier = Guid.NewGuid().ToString();
}
return 6;
}
}
}

View File

@@ -9,6 +9,7 @@ namespace Orchard.Projections.Models {
}
public virtual int Id { get; set; }
public virtual string GUIdentifier { get; set; }
public virtual string Description { get; set; }
public virtual string Category { get; set; }
public virtual string Type { get; set; }

View File

@@ -141,6 +141,10 @@
<Name>Orchard.Core</Name>
<Private>$(MvcBuildViews)</Private>
</ProjectReference>
<ProjectReference Include="..\Orchard.ContentTypes\Orchard.ContentTypes.csproj">
<Project>{0E7646E8-FE8F-43C1-8799-D97860925EC4}</Project>
<Name>Orchard.ContentTypes</Name>
</ProjectReference>
<ProjectReference Include="..\Orchard.Forms\Orchard.Forms.csproj">
<Project>{642A49D7-8752-4177-80D6-BFBBCFAD3DE0}</Project>
<Name>Orchard.Forms</Name>
@@ -183,6 +187,8 @@
<Compile Include="Services\DraftFieldIndexService.cs" />
<Compile Include="Services\IDraftFieldIndexService.cs" />
<Compile Include="Services\IProjectionManagerExtension.cs" />
<Compile Include="Settings\ProjectionPartEditorEvents.cs" />
<Compile Include="Settings\ProjectionPartSettings.cs" />
<Compile Include="Shapes.cs" />
<Compile Include="Descriptors\Layout\LayoutComponentResult.cs" />
<Compile Include="Descriptors\Layout\LayoutContext.cs" />
@@ -331,6 +337,7 @@
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
<Content Include="Views\DefinitionTemplates\ProjectionPartSettings.cshtml" />
</ItemGroup>
<PropertyGroup>
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">10.0</VisualStudioVersion>

View File

@@ -0,0 +1,264 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Orchard.ContentManagement;
using Orchard.ContentManagement.MetaData;
using Orchard.ContentManagement.MetaData.Builders;
using Orchard.ContentManagement.MetaData.Models;
using Orchard.ContentManagement.ViewModels;
using Orchard.ContentTypes.Events;
using Orchard.Core.Title.Models;
using Orchard.Data;
using Orchard.Forms.Services;
using Orchard.Localization;
using Orchard.Projections.Descriptors.Layout;
using Orchard.Projections.Models;
using Orchard.Projections.Services;
using Orchard.Projections.ViewModels;
using Orchard.UI.Notify;
namespace Orchard.Projections.Settings {
public class ProjectionPartEditorEvents : ContentDefinitionEditorEventsBase, IContentDefinitionEventHandler {
private readonly IProjectionManagerExtension _projectionManager;
private readonly IContentManager _contentManager;
private readonly IRepository<LayoutRecord> _layoutRepository;
private readonly IContentDefinitionManager _contentDefinitionManager;
public ProjectionPartEditorEvents(
IOrchardServices services,
IProjectionManagerExtension projectionManager,
IContentManager contentManager,
IRepository<LayoutRecord> layoutRepository,
IContentDefinitionManager contentDefinitionManager) {
_projectionManager = projectionManager;
_contentManager = contentManager;
_layoutRepository = layoutRepository;
_contentDefinitionManager = contentDefinitionManager;
Services = services;
T = NullLocalizer.Instance;
}
public Localizer T { get; set; }
public IOrchardServices Services { get; set; }
public override IEnumerable<TemplateViewModel> TypePartEditor(ContentTypePartDefinition definition) {
if (definition.PartDefinition.Name == "ProjectionPart") {
var model = definition.Settings.GetModel<ProjectionPartSettings>();
model.QueryRecordEntries = GetQueriesRecordEntry();
if (!string.IsNullOrWhiteSpace(model.FilterQueryRecordId)) {
model.FilterQueryRecordsId = model.FilterQueryRecordId.Split('&');
}
yield return DefinitionTemplate(model);
}
}
public override IEnumerable<TemplateViewModel> TypePartEditorUpdate(ContentTypePartDefinitionBuilder builder, IUpdateModel updateModel) {
if (builder.Name != "ProjectionPart") {
yield break;
}
var model = new ProjectionPartSettings();
model.QueryRecordEntries = GetQueriesRecordEntry();
if(updateModel.TryUpdateModel(model, "ProjectionPartSettings", null, null)) {
if (model.FilterQueryRecordsId != null && model.FilterQueryRecordsId.Count()>0) {
// check if default query selected is in filter queries list
if (!model.FilterQueryRecordsId.Contains(model.QueryLayoutRecordId) && model.QueryLayoutRecordId!="-1") {
updateModel.AddModelError("ProjectionPart", T("The default query must be one of the selected queries"));
}
// also save the identity part of the query and guid of the layout to be used in the import
model.IdentityQueryLayoutRecord = GetIdentityQueryLayout(model.QueryLayoutRecordId);
model.FilterQueryRecordId = string.Join("&", model.FilterQueryRecordsId);
List<string> identityForFilterQuery = new List<string>();
foreach (var record in model.FilterQueryRecordsId) {
identityForFilterQuery.Add(GetIdentityQueryLayout(record));
}
model.IdentityFilterQueryRecord = string.Join("&", identityForFilterQuery);
}
builder
.WithSetting("ProjectionPartSettings.QueryLayoutRecordId", model.QueryLayoutRecordId)
.WithSetting("ProjectionPartSettings.IdentityQueryLayoutRecord", model.IdentityQueryLayoutRecord)
.WithSetting("ProjectionPartSettings.FilterQueryRecordId", model.FilterQueryRecordId)
.WithSetting("ProjectionPartSettings.IdentityFilterQueryRecord", model.IdentityFilterQueryRecord)
.WithSetting("ProjectionPartSettings.Items", model.Items.ToString())
.WithSetting("ProjectionPartSettings.LockEditingItems", model.LockEditingItems.ToString())
.WithSetting("ProjectionPartSettings.Skip", model.Skip.ToString())
.WithSetting("ProjectionPartSettings.LockEditingSkip", model.LockEditingSkip.ToString())
.WithSetting("ProjectionPartSettings.MaxItems", model.MaxItems.ToString())
.WithSetting("ProjectionPartSettings.LockEditingMaxItems", model.LockEditingMaxItems.ToString())
.WithSetting("ProjectionPartSettings.PagerSuffix", model.PagerSuffix)
.WithSetting("ProjectionPartSettings.LockEditingPagerSuffix", model.LockEditingPagerSuffix.ToString())
.WithSetting("ProjectionPartSettings.DisplayPager", model.DisplayPager.ToString())
.WithSetting("ProjectionPartSettings.LockEditingDisplayPager", model.LockEditingDisplayPager.ToString());
}
yield return DefinitionTemplate(model);
}
#region Implementation interface
public void ContentFieldAttached(ContentFieldAttachedContext context) {
}
public void ContentFieldDetached(ContentFieldDetachedContext context) {
}
public void ContentPartAttached(ContentPartAttachedContext context) {
}
public void ContentPartCreated(ContentPartCreatedContext context) {
}
public void ContentPartDetached(ContentPartDetachedContext context) {
}
public void ContentPartImported(ContentPartImportedContext context) {
}
public void ContentPartImporting(ContentPartImportingContext context) {
}
public void ContentPartRemoved(ContentPartRemovedContext context) {
}
public void ContentTypeCreated(ContentTypeCreatedContext context) {
}
public void ContentTypeImported(ContentTypeImportedContext context) {
var part = context.ContentTypeDefinition.Parts
.ToList()
.Where(p => p.PartDefinition.Name == "ProjectionPart")
.FirstOrDefault();
if (part != null) {
var settings = part.Settings.GetModel<ProjectionPartSettings>();
// from identity part of the query and guid of the layout find reference
settings.QueryLayoutRecordId = GetQueryLayoutRecord(settings.IdentityQueryLayoutRecord);
List<string> identityForFilterQuery = new List<string>();
foreach (var record in settings.IdentityFilterQueryRecord.Split('&').ToList()) {
var correctId = GetQueryLayoutRecord(record);
if (!string.IsNullOrEmpty(correctId)) {
identityForFilterQuery.Add(correctId);
}
}
settings.FilterQueryRecordId = string.Join("&", identityForFilterQuery);
_contentDefinitionManager.AlterTypeDefinition(context.ContentTypeDefinition.Name, cfg => cfg
.WithPart(part.PartDefinition.Name,
pb => pb
.WithSetting("ProjectionPartSettings.QueryLayoutRecordId", settings.QueryLayoutRecordId)
.WithSetting("ProjectionPartSettings.FilterQueryRecordId", settings.FilterQueryRecordId))
);
}
}
public void ContentTypeImporting(ContentTypeImportingContext context) {
}
public void ContentTypeRemoved(ContentTypeRemovedContext context) {
}
#endregion
private string GetQueryLayoutRecord(string record) {
var ids = record.Split(';');
if (ids.Count() == 1) {
// if is present only -1, the default query has not been selected
return ids[0];
}
else {
string stringIds = string.Empty;
var ciIdentity = _contentManager.ResolveIdentity(new ContentIdentity(ids[0]));
if (ciIdentity != null) {
stringIds = ciIdentity.Id.ToString() + ";";
if (ids[1] == "-1") {
// default layout
stringIds += "-1";
}
else {
var recordLayout = _layoutRepository.Fetch(l => l.GUIdentifier == ids[1]).FirstOrDefault();
if (recordLayout != null) {
stringIds += recordLayout.Id.ToString();
}
}
}
return stringIds;
}
}
private string GetIdentityQueryLayout(string record) {
var ids = record.Split(';');
if (ids.Count() == 1) {
// if is present only -1, the default query has not been selected
return ids[0];
}
else {
// ids[0] is id of query
// ids[1] is record id of layout
var identityQueryLayout = string.Empty;
// identity part to identify the query
var content = _contentManager.Get(int.Parse(ids[0]));
if (content != null) {
var identity = _contentManager.GetItemMetadata(content).Identity;
if (identity != null) {
identityQueryLayout = identity.ToString() + ";";
}
else {
Services.Notifier.Error(T("ProjectionPart - Query - The loaded id {0} does not exist", ids[0]));
}
}
// guid id to identify the layout
if (ids[1] == "-1") {
// default layout
identityQueryLayout += ids[1];
}
else {
var layoutRecord = _layoutRepository.Get(int.Parse(ids[1]));
if (layoutRecord != null) {
identityQueryLayout += layoutRecord.GUIdentifier;
}
else {
Services.Notifier.Error(T("ProjectionPart - Layout of query - The loaded id {0} does not exist", ids[1]));
}
}
return identityQueryLayout;
}
}
private IEnumerable<QueryRecordEntry> GetQueriesRecordEntry() {
// populating the list of queries and layouts
var layouts = _projectionManager.DescribeLayouts().SelectMany(x => x.Descriptors).ToList();
List<QueryRecordEntry> records = new List<QueryRecordEntry>();
records.Add(new QueryRecordEntry {
Id = -1,
Name = T("No default").Text,
LayoutRecordEntries = new List<LayoutRecordEntry>()
});
records.AddRange(Services.ContentManager.Query<QueryPart, QueryPartRecord>().Join<TitlePartRecord>().OrderBy(x => x.Title).List()
.Select(x => new QueryRecordEntry {
Id = x.Id,
Name = x.Name,
LayoutRecordEntries = x.Layouts
.Select(l => new LayoutRecordEntry {
Id = l.Id,
Description = GetLayoutDescription(layouts, l)
})
.ToList()
}));
return records;
}
private string GetLayoutDescription(IEnumerable<LayoutDescriptor> layouts, LayoutRecord l) {
var descriptor = layouts.FirstOrDefault(x => l.Category == x.Category && l.Type == x.Type);
return String.IsNullOrWhiteSpace(l.Description) ? descriptor.Display(new LayoutContext { State = FormParametersHelper.ToDynamic(l.State) }).Text : l.Description;
}
}
}

View File

@@ -0,0 +1,31 @@
using System.Collections.Generic;
using System.ComponentModel;
using Orchard.Projections.ViewModels;
namespace Orchard.Projections.Settings {
public class ProjectionPartSettings {
public ProjectionPartSettings() {
FilterQueryRecordsId = new List<string>();
}
public string QueryLayoutRecordId { get; set; }
// saved identity part for import
public string IdentityQueryLayoutRecord { get; set; }
public IEnumerable<QueryRecordEntry> QueryRecordEntries { get; set; }
public IEnumerable<string> FilterQueryRecordsId { get; set; }
public string FilterQueryRecordId { get; set; }
// saved identity part for import
public string IdentityFilterQueryRecord { get; set; }
public int Items { get; set; }
public bool LockEditingItems { get; set; }
[DisplayName("Offset")]
public int Skip { get; set; }
public bool LockEditingSkip { get; set; }
public int MaxItems { get; set; }
public bool LockEditingMaxItems { get; set; }
public string PagerSuffix { get; set; }
public bool LockEditingPagerSuffix { get; set; }
public bool DisplayPager { get; set; }
public bool LockEditingDisplayPager { get; set; }
}
}

View File

@@ -1,4 +1,5 @@
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
namespace Orchard.Projections.ViewModels {
@@ -10,7 +11,7 @@ namespace Orchard.Projections.ViewModels {
[Required, Range(0, int.MaxValue)]
public int ItemsPerPage { get; set; }
[Required, Range(0, int.MaxValue)]
[Required, Range(0, int.MaxValue),DisplayName("Offset")]
public int Skip { get; set; }
public string PagerSuffix { get; set; }
@@ -24,6 +25,17 @@ namespace Orchard.Projections.ViewModels {
public string QueryLayoutRecordId { get; set; }
public IEnumerable<QueryRecordEntry> QueryRecordEntries { get; set; }
public IEnumerable<QueryRecordFilterEntry> QueryRecordIdFilterEntries { get; set; }
public int PartId { get; set; }
// manage Lock items
public bool LockEditingItems { get; set; }
public bool LockEditingSkip { get; set; }
public bool LockEditingMaxItems { get; set; }
public bool LockEditingPagerSuffix { get; set; }
public bool LockEditingDisplayPager { get; set; }
}
public class QueryRecordEntry {
@@ -36,4 +48,8 @@ namespace Orchard.Projections.ViewModels {
public int Id { get; set; }
public string Description { get; set; }
}
public class QueryRecordFilterEntry {
public string Id { get; set; }
public string LayoutId { get; set; }
}
}

View File

@@ -0,0 +1,112 @@
@model Orchard.Projections.Settings.ProjectionPartSettings
@using Orchard.Projections.Models;
@using Orchard.Projections.ViewModels;
<fieldset>
@Html.LabelFor(m => m.QueryLayoutRecordId, T("Default Query"))
<select id="@Html.FieldIdFor(m => m.QueryLayoutRecordId)" name="@Html.FieldNameFor(m => m.QueryLayoutRecordId)">
@{
// no default query
var defaultQueryRecord = Model.QueryRecordEntries.Where(q => q.Id == -1).FirstOrDefault();
@Html.SelectOption(Model.QueryLayoutRecordId, defaultQueryRecord.Id.ToString(), T("No default query").Text)
}
@foreach (QueryRecordEntry queryRecord in Model.QueryRecordEntries.Where(q => q.Id != -1).OrderBy(x => x.Name)) {
<optgroup label="@queryRecord.Name">
@Html.SelectOption(Model.QueryLayoutRecordId, queryRecord.Id + ";-1", queryRecord.Name + " " + T("(Default Layout)").Text)
@foreach (LayoutRecordEntry layoutRecord in queryRecord.LayoutRecordEntries.OrderBy(x => x.Description)) {
@Html.SelectOption(Model.QueryLayoutRecordId, queryRecord.Id + ";" + layoutRecord.Id, queryRecord.Name + " " + T("({0})", layoutRecord.Description).Text)
}
</optgroup>
}
</select>
<span class="hint">@T("The query to display.")</span>
</fieldset>
<fieldset>
<span class="hint">@T("Select lock editing to prevent the user from editing the default choice")</span>
<div>
<div class="row-settings-projection-part">
<div class="col-settings-projection-part">
@Html.LabelFor(m => m.Items, T("Items to display"))
@Html.TextBoxFor(m => m.Items, new { @class = "text small" })
</div>
<div class="col-settings-projection-part lock-editing-projection-part-field">
@Html.CheckBoxFor(m => m.LockEditingItems)
<label class="forcheckbox" for="@Html.FieldIdFor(m => m.LockEditingItems)">@T("Lock Editing")</label>
</div>
</div>
<span class="hint">@T("The number of items to display. Enter 0 for no limit. When using pagination, this is the number of items per page.")</span>
</div>
<div>
<div class="row-settings-projection-part">
<div class="col-settings-projection-part">
@Html.LabelFor(m => m.Skip, T("Offset"))
@Html.TextBoxFor(m => m.Skip, new { @class = "text small" })
</div>
<div class="col-settings-projection-part lock-editing-projection-part-field">
@Html.CheckBoxFor(m => m.LockEditingSkip)
<label class="forcheckbox" for="@Html.FieldIdFor(m => m.LockEditingSkip)">@T("Lock Editing")</label>
</div>
</div>
<span class="hint">@T("The number of items to skip (e.g., if 2 is entered, the first 2 items won't be diplayed).")</span>
</div>
<div>
<div class="row-settings-projection-part">
<div class="col-settings-projection-part">
@Html.LabelFor(m => m.MaxItems, T("Maximum items"))
@Html.TextBoxFor(m => m.MaxItems, new { @class = "text small" })
</div>
<div class="col-settings-projection-part lock-editing-projection-part-field">
@Html.CheckBoxFor(m => m.LockEditingMaxItems)
<label class="forcheckbox" for="@Html.FieldIdFor(m => m.LockEditingMaxItems)">@T("Lock Editing")</label>
</div>
</div>
<span class="hint">@T("Maximum number of items which can be queried at once. Use 0 for unlimited. This is only used as a failsafe when the number of items comes from a user-provided source such as the query string.")</span>
</div>
<div>
<div class="row-settings-projection-part">
<div class="col-settings-projection-part">
@Html.LabelFor(m => m.PagerSuffix, T("Suffix"))
@Html.TextBoxFor(m => m.PagerSuffix, new { @class = "text" })
</div>
<div class="col-settings-projection-part lock-editing-projection-part-field">
@Html.CheckBoxFor(m => m.LockEditingPagerSuffix)
<label class="forcheckbox" for="@Html.FieldIdFor(m => m.LockEditingPagerSuffix)">@T("Lock Editing")</label>
</div>
</div>
<span class="hint">@T("Optional. Provide a suffix to use when multiple pagers are displayed on the same page, e.g., when using multiple Projection Widgets, or to define alternates.")</span>
</div>
<div>
<div class="row-settings-projection-part">
<div class="col-settings-projection-part">
@Html.CheckBoxFor(m => m.DisplayPager)
<label class="forcheckbox" for="@Html.FieldIdFor(m => m.DisplayPager)">@T("Show pager")</label>
</div>
<div class="col-settings-projection-part">
@Html.CheckBoxFor(m => m.LockEditingDisplayPager)
<label class="forcheckbox" for="@Html.FieldIdFor(m => m.LockEditingDisplayPager)">@T("Lock Editing")</label>
</div>
</div>
<span class="hint">@T("Check to add a pager to the list.")</span>
</div>
</fieldset>
<fieldset>
@Html.LabelFor(m => m.FilterQueryRecordId, T("Filter Queries"))
<select id="@Html.FieldIdFor(m => m.FilterQueryRecordsId)" multiple="multiple" size="10" name="@Html.FieldNameFor(m => m.FilterQueryRecordsId)">
@foreach (QueryRecordEntry queryRecord in Model.QueryRecordEntries.Where(q => q.Id != -1).OrderBy(x => x.Name)) {
<optgroup label="@queryRecord.Name">
@Html.SelectOption(queryRecord.Id + ";-1", Model.FilterQueryRecordsId.Contains(queryRecord.Id + ";-1"), queryRecord.Name + " " + T("(Default Layout)").Text)
@foreach (LayoutRecordEntry layoutRecord in queryRecord.LayoutRecordEntries.OrderBy(x => x.Description)) {
@Html.SelectOption(queryRecord.Id + ";" + layoutRecord.Id, Model.FilterQueryRecordsId.Contains(queryRecord.Id + ";" + layoutRecord.Id), queryRecord.Name + " " + T("({0})", layoutRecord.Description).Text)
}
</optgroup>
}
</select>
<span class="hint">@T("Select which queries to display to the user. If there are no selections, all queries will be used.")</span>
</fieldset>

View File

@@ -4,71 +4,140 @@
@{
var selectedQueryRecordId = -1;
var filterQuery = Model.QueryRecordIdFilterEntries.Any();
var checkQuery = false;
}
<fieldset>
@Html.LabelFor(m => m.QueryLayoutRecordId, T("For Query"))
<select id="@Html.FieldIdFor(m => m.QueryLayoutRecordId)" name="@Html.FieldNameFor(m => m.QueryLayoutRecordId)">
@foreach (QueryRecordEntry queryRecord in Model.QueryRecordEntries.OrderBy(x => x.Name)) {
<optgroup label="@queryRecord.Name">
@Html.SelectOption(Model.QueryLayoutRecordId, queryRecord.Id + ";-1", queryRecord.Name + " " + T("(Default Layout)").Text)
@if (Model.QueryLayoutRecordId == queryRecord.Id + ";-1") {
selectedQueryRecordId = queryRecord.Id;
}
@helper HintFromLockedField(string errorMessage) {
<span class="hint">@errorMessage</span>
<span class="hint">@T("This field is locked from the settings, cannot be modified.")</span>
}
@foreach (LayoutRecordEntry layoutRecord in queryRecord.LayoutRecordEntries.OrderBy(x => x.Description)) {
@Html.SelectOption(Model.QueryLayoutRecordId, queryRecord.Id + ";" + layoutRecord.Id, queryRecord.Name + " " + T("({0})", layoutRecord.Description).Text)
if (Model.QueryLayoutRecordId == queryRecord.Id + ";" + layoutRecord.Id) {
selectedQueryRecordId = queryRecord.Id;
<fieldset>
@Html.LabelFor(m => m.QueryLayoutRecordId, T("For Query"))
@{
// if any values, use default list of the settings
<select id="@Html.FieldIdFor(m => m.QueryLayoutRecordId)" name="@Html.FieldNameFor(m => m.QueryLayoutRecordId)">
@foreach (QueryRecordEntry queryRecord in Model.QueryRecordEntries.OrderBy(x => x.Name)) {
// check condition for design option group
bool designDefaultQuery = Model.QueryRecordIdFilterEntries.Any(x => x.Id == queryRecord.Id.ToString() && x.LayoutId == "-1");
bool designAnotherLayout = Model.QueryRecordIdFilterEntries.Any(x => queryRecord.LayoutRecordEntries.Select(q => q.Id.ToString()).Contains(x.LayoutId));
if (!filterQuery || designDefaultQuery || designAnotherLayout) {
<optgroup label="@queryRecord.Name">
@if (!filterQuery || designDefaultQuery) {
@Html.SelectOption(Model.QueryLayoutRecordId, queryRecord.Id + ";-1", queryRecord.Name + " " + T("(Default Layout)").Text)
if (Model.QueryLayoutRecordId == queryRecord.Id + ";-1") {
selectedQueryRecordId = queryRecord.Id;
checkQuery = true;
}
}
@foreach (LayoutRecordEntry layoutRecord in queryRecord.LayoutRecordEntries.OrderBy(x => x.Description)) {
if (!filterQuery || Model.QueryRecordIdFilterEntries.Any(x => x.Id == queryRecord.Id.ToString() && x.LayoutId == layoutRecord.Id.ToString())) {
@Html.SelectOption(Model.QueryLayoutRecordId, queryRecord.Id + ";" + layoutRecord.Id, queryRecord.Name + " " + T("({0})", layoutRecord.Description).Text)
if (Model.QueryLayoutRecordId == queryRecord.Id + ";" + layoutRecord.Id) {
selectedQueryRecordId = queryRecord.Id;
checkQuery = true;
}
}
}
</optgroup>
}
}
</optgroup>
</select>
if (!checkQuery && Model.PartId != 0) {
<label class="info">@T("The previously selected query is no longer available.")</label>
}
}
</select>
@if (selectedQueryRecordId != -1) {
@Html.ActionLink(T("Edit Query").Text, "Edit", new { area = "Orchard.Projections", id = selectedQueryRecordId }, new { })
}
<span class="hint">@T("The query to display.")</span>
</fieldset>
@if (selectedQueryRecordId != -1) {
@Html.ActionLink(T("Edit Query").Text, "Edit", new { area = "Orchard.Projections", id = selectedQueryRecordId }, new { })
}
<span class="hint">@T("The query to display.")</span>
</fieldset>
<fieldset>
<div>
@Html.LabelFor(m => m.Items, T("Items to display"))
@Html.TextBoxFor(m => m.Items, new { @class = "text small" })
<span class="hint">@T("The number of items to display. Enter 0 for no limit. When using pagination, this is the number of items per page.")</span>
@if (Model.LockEditingItems) {
<label class="sub">@T("Items to display"): </label><span>@Model.Items</span>
@Html.HiddenFor(m => m.Items)
@HintFromLockedField(T("The number of items to display. If equals 0 no limit. When using pagination, this is the number of items per page.").Text)
}
else {
@Html.LabelFor(m => m.Items, T("Items to display"))
@Html.TextBoxFor(m => m.Items, new { @class = "text small" })
<span class="hint">@T("The number of items to display. Enter 0 for no limit. When using pagination, this is the number of items per page.")</span>
}
</div>
<div>
@Html.LabelFor(m => m.Skip, T("Offset"))
@Html.TextBoxFor(m => m.Skip, new { @class = "text small" })
<span class="hint">@T("The number of items to skip (e.g., if 2 is entered, the first 2 items won't be diplayed).")</span>
@if (Model.LockEditingSkip) {
<label class="sub">@T("Offset"): </label><span>@Model.Skip</span>
@Html.HiddenFor(m => m.Skip)
@HintFromLockedField(T("The number of items to skip (e.g., if 2 is entered, the first 2 items won't be diplayed).").Text)
}
else {
@Html.LabelFor(m => m.Skip, T("Offset"))
@Html.TextBoxFor(m => m.Skip, new { @class = "text small" })
<span class="hint">@T("The number of items to skip (e.g., if 2 is entered, the first 2 items won't be diplayed).")</span>
}
</div>
<div>
@Html.LabelFor(m => m.MaxItems, T("Maximum items"))
@Html.TextBoxFor(m => m.MaxItems, new { @class = "text small" })
<span class="hint">@T("Maximum number of items which can be queried at once. Use 0 for unlimited. This is only used as a failsafe when the number of items comes from a user-provided source such as the query string.")</span>
@if (Model.LockEditingMaxItems) {
<label class="sub">@T("Maximum items"): </label><span>@Model.MaxItems</span>
@Html.HiddenFor(m => m.MaxItems)
@HintFromLockedField(T("Maximum number of items which can be queried at once. Use 0 for unlimited. This is only used as a failsafe when the number of items comes from a user-provided source such as the query string.").Text)
}
else {
@Html.LabelFor(m => m.MaxItems, T("Maximum items"))
@Html.TextBoxFor(m => m.MaxItems, new { @class = "text small" })
<span class="hint">@T("Maximum number of items which can be queried at once. Use 0 for unlimited. This is only used as a failsafe when the number of items comes from a user-provided source such as the query string.")</span>
}
</div>
<div>
@Html.LabelFor(m => m.PagerSuffix, T("Suffix"))
@Html.TextBoxFor(m => m.PagerSuffix, new { @class = "text" })
<span class="hint">@T("Optional. Provide a suffix to use when multiple pagers are displayed on the same page, e.g., when using multiple Projection Widgets, or to define alternates.")</span>
@if (Model.LockEditingPagerSuffix) {
if (!string.IsNullOrEmpty(Model.PagerSuffix)) {
<label class="sub">@T("Suffix"): </label><span>@Model.PagerSuffix</span>
@HintFromLockedField(T("Optional. Provide a suffix to use when multiple pagers are displayed on the same page, e.g., when using multiple Projection Widgets, or to define alternates.").Text)
}
@Html.HiddenFor(m => m.PagerSuffix)
}
else {
@Html.LabelFor(m => m.PagerSuffix, T("Suffix"))
@Html.TextBoxFor(m => m.PagerSuffix, new { @class = "text small" })
<span class="hint">@T("Optional. Provide a suffix to use when multiple pagers are displayed on the same page, e.g., when using multiple Projection Widgets, or to define alternates.")</span>
}
</div>
<div>
@Html.CheckBoxFor(m => m.DisplayPager)
<label class="forcheckbox" for="@Html.FieldIdFor(m => m.DisplayPager)">@T("Show pager")</label>
<span class="hint">@T("Check to add a pager to the list.")</span>
@if (Model.LockEditingDisplayPager) {
<label class="sub">@T("Show pager"): </label>
if (Model.DisplayPager) {
<span>@T("True")</span>
}
else {
<span>@T("False")</span>
}
@Html.HiddenFor(m => m.DisplayPager)
@HintFromLockedField(T("Flag used to add a pager to the list.").Text)
}
else {
@Html.CheckBoxFor(m => m.DisplayPager)
<label class="forcheckbox" for="@Html.FieldIdFor(m => m.DisplayPager)">@T("Show pager")</label>
<span class="hint">@T("Check to add a pager to the list.")</span>
}
</div>
</fieldset>
@using (Script.Foot()) {
<script type="text/javascript">
//<![CDATA[
(function ($) {
$("fieldset legend").expandoControl(function (controller) { return controller.nextAll(".expando"); }, { collapse: true, remember: false });
})(jQuery);
<script type="text/javascript">
//<![CDATA[
(function ($) {
$("fieldset legend").expandoControl(function (controller) { return controller.nextAll(".expando"); }, { collapse: true, remember: false });
})(jQuery);
//]]>
</script>
</script>
}