Skip to content

Commit

Permalink
Feature/maxlengthsetting (#8719)
Browse files Browse the repository at this point in the history
* added MaxLength setting for TextField

# Conflicts:
#	src/Orchard.Web/Modules/Orchard.Taxonomies/Settings/TaxonomyFieldEditorEvents.cs

* added MaxLength setting for TitlePart

* added missing files

* Removed where clause

* changed title length to a constant and updated the recipe

* added comment to remind people to update the migration when they change the constant introduced previously

* fixed hint text for title

* fixed maxLength initialization in TitlePartSettings.cshtml

* MaxTitleLength constant is now Pascal case

* Correction on constant spelling in TitlePartSettings shape.

---------

Co-authored-by: Andrea Piovanelli <[email protected]>
  • Loading branch information
AgostiniAlessandro and AndreaPiovanelli authored Feb 21, 2024
1 parent eb09ab7 commit 44bfa39
Show file tree
Hide file tree
Showing 18 changed files with 193 additions and 31 deletions.
11 changes: 11 additions & 0 deletions src/Orchard.Web/Core/Common/Drivers/TextFieldDriver.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
using Orchard.Core.Common.ViewModels;
using Orchard.Localization;
using Orchard.Services;
using Orchard.Utility.Extensions;

namespace Orchard.Core.Common.Drivers {
public class TextFieldDriver : ContentFieldDriver<TextField> {
Expand Down Expand Up @@ -71,6 +72,16 @@ protected override DriverResult Editor(ContentPart part, TextField field, IUpdat
if (settings.Required && String.IsNullOrWhiteSpace(field.Value)) {
updater.AddModelError("Text", T("The field {0} is mandatory", T(field.DisplayName)));
}

if (settings.MaxLength > 0) {

var value = new HtmlString(_htmlFilters.Aggregate(field.Value, (text, filter) => filter.ProcessContent(text, settings.Flavor)))
.ToString().RemoveTags();

if (value.Length > settings.MaxLength) {
updater.AddModelError("Text", T("The maximum allowed length for the field {0} is {1}", T(field.DisplayName), settings.MaxLength));
}
}
}

return Editor(part, field, shapeHelper);
Expand Down
6 changes: 5 additions & 1 deletion src/Orchard.Web/Core/Common/Settings/TextFieldSettings.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System.ComponentModel.DataAnnotations;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;

namespace Orchard.Core.Common.Settings {

Expand All @@ -8,5 +9,8 @@ public class TextFieldSettings {
public bool Required { get; set; }
public string Hint { get; set; }
public string DefaultValue { get; set; }
[Range(0, int.MaxValue)]
[DisplayName("Maximum Length")]
public int MaxLength { get; set; }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,10 @@ public override IEnumerable<TemplateViewModel> PartFieldEditorUpdate(ContentPart
builder.WithSetting("TextFieldSettings.Hint", model.Settings.Hint);
builder.WithSetting("TextFieldSettings.Required", model.Settings.Required.ToString(CultureInfo.InvariantCulture));
builder.WithSetting("TextFieldSettings.DefaultValue", model.Settings.DefaultValue);

yield return DefinitionTemplate(model);
builder.WithSetting("TextFieldSettings.MaxLength", model.Settings.MaxLength.ToString());
}

yield return DefinitionTemplate(model);
}
}
}
13 changes: 10 additions & 3 deletions src/Orchard.Web/Core/Common/Views/Body-Large.Editor.cshtml
Original file line number Diff line number Diff line change
@@ -1,7 +1,14 @@
@{
var htmlAttributes = new Dictionary<string, object> {
{"class", "text large"}
};
var htmlAttributes = (Dictionary<string, object>)Model.HtmlAttributes;

if (htmlAttributes == null) {
htmlAttributes = new Dictionary<string, object> {
{"class", "text large"}
};
}
else {
htmlAttributes["class"] = "text large";
}

if (Model.Required == true) {
htmlAttributes["required"] = "required";
Expand Down
13 changes: 10 additions & 3 deletions src/Orchard.Web/Core/Common/Views/Body-Small.Editor.cshtml
Original file line number Diff line number Diff line change
@@ -1,7 +1,14 @@
@{
var htmlAttributes = new Dictionary<string, object> {
{"class", "text small"}
};
var htmlAttributes = (Dictionary<string, object>)Model.HtmlAttributes;

if (htmlAttributes == null) {
htmlAttributes = new Dictionary<string, object> {
{"class", "text small"}
};
}
else {
htmlAttributes["class"] = "text small";
}

if (Model.Required == true) {
htmlAttributes["required"] = "required";
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
@{
var htmlAttributes = new Dictionary<string, object>();

var htmlAttributes = (Dictionary<string, object>)Model.HtmlAttributes;

if (htmlAttributes == null) {
htmlAttributes = new Dictionary<string, object>();
}

if (Model.Required == true) {
htmlAttributes["required"] = "required";
Expand Down
13 changes: 10 additions & 3 deletions src/Orchard.Web/Core/Common/Views/Body-Wide.Editor.cshtml
Original file line number Diff line number Diff line change
@@ -1,7 +1,14 @@
@{
var htmlAttributes = new Dictionary<string, object> {
{"class", "text medium"}
};
var htmlAttributes = (Dictionary<string, object>)Model.HtmlAttributes;

if (htmlAttributes == null) {
htmlAttributes = new Dictionary<string, object> {
{"class", "text medium"}
};
}
else {
htmlAttributes["class"] = "text medium";
}

if (Model.Required == true) {
htmlAttributes["required"] = "required";
Expand Down
12 changes: 9 additions & 3 deletions src/Orchard.Web/Core/Common/Views/Body.Editor.cshtml
Original file line number Diff line number Diff line change
@@ -1,10 +1,16 @@
@using Orchard.Utility.Extensions;
@{
string editorFlavor = Model.EditorFlavor;
var htmlAttributes = (Dictionary<string, object>)Model.HtmlAttributes;

var htmlAttributes = new Dictionary<string, object> {
{"class", editorFlavor.HtmlClassify()}
};
if (htmlAttributes == null) {
htmlAttributes = new Dictionary<string, object> {
{"class", editorFlavor.HtmlClassify()}};

}
else {
htmlAttributes["class"] = editorFlavor.HtmlClassify();
}

if (Model.Required == true) {
htmlAttributes["required"] = "required";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,12 @@
@Html.ValidationMessageFor(m => m.Settings.Flavor)
</div>
</fieldset>
<fieldset>
<label for="@Html.FieldIdFor(m => m.Settings.MaxLength)">@T("Maximum length")</label>
@Html.EditorFor(m => m.Settings.MaxLength, new { htmlAttributes = new { min = 0 } })
<span class="hint">@T("Maximum length allowed for this field. Setting the value to 0 means unlimited length.")</span>
@Html.ValidationMessageFor(m => m.Settings.MaxLength)
</fieldset>
<fieldset>
<div>
@Html.CheckBoxFor(m => m.Settings.Required) <label for="@Html.FieldIdFor(m => m.Settings.Required)" class="forcheckbox">@T("Required")</label>
Expand All @@ -21,4 +27,4 @@
</fieldset>
<fieldset>
@Display.DefinitionTemplate(TemplateName: "TextFieldDefaultValueEditor", Model: Model)
</fieldset>
</fieldset>
Original file line number Diff line number Diff line change
@@ -1,15 +1,26 @@
@model Orchard.Core.Common.ViewModels.TextFieldDriverViewModel
@{
var maxLength = Model.Settings.MaxLength > 0 ? Model.Settings.MaxLength.ToString() : "";
}

<fieldset>
<label for="@Html.FieldIdFor(m => m.Text)" @if(Model.Settings.Required) { <text>class="required"</text> }>@Model.Field.DisplayName</label>
<label for="@Html.FieldIdFor(m => m.Text)" @if (Model.Settings.Required) { <text> class="required" </text> }>@Model.Field.DisplayName</label>
@if (String.IsNullOrWhiteSpace(Model.Settings.Flavor)) {
@(Model.Settings.Required ? Html.TextBoxFor(m => m.Text, new {@class = "text", required = "required"}) : Html.TextBoxFor(m => m.Text, new {@class = "text"}))
@(Model.Settings.Required
? Html.TextBoxFor(m => m.Text, new {@class = "text", required = "required", maxlength = maxLength})
: Html.TextBoxFor(m => m.Text, new {@class = "text", maxlength = maxLength }))
@Html.ValidationMessageFor(m => m.Text)
}
else {
@Display.Body_Editor(Text: Model.Text, EditorFlavor: Model.Settings.Flavor, Required: Model.Settings.Required, ContentItem: Model.ContentItem, Field: Model.Field)

var htmlAttributes = new Dictionary<string, object> {
{"maxlength", maxLength}
};

@Display.Body_Editor(Text: Model.Text, EditorFlavor: Model.Settings.Flavor, Required: Model.Settings.Required,
ContentItem: Model.ContentItem, Field: Model.Field, HtmlAttributes: htmlAttributes)
}
@if (HasText(Model.Settings.Hint)) {
<span class="hint">@Model.Settings.Hint</span>
<span class="hint">@Model.Settings.Hint</span>
}
</fieldset>
3 changes: 3 additions & 0 deletions src/Orchard.Web/Core/Orchard.Core.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -293,6 +293,8 @@
<Compile Include="Title\Migrations.cs" />
<Compile Include="Title\Models\TitlePart.cs" />
<Compile Include="Title\Models\TitlePartRecord.cs" />
<Compile Include="Title\Settings\TitlePartSettings.cs" />
<Compile Include="Title\Settings\TitlePartSettingsEvents.cs" />
<Compile Include="XmlRpc\Controllers\HomeController.cs" />
<Compile Include="XmlRpc\Controllers\LiveWriterController.cs" />
<Compile Include="XmlRpc\IXmlRpcDriver.cs" />
Expand Down Expand Up @@ -612,6 +614,7 @@
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
<Content Include="Title\Views\DefinitionTemplates\TitlePartSettings.cshtml" />
</ItemGroup>
<PropertyGroup>
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">10.0</VisualStudioVersion>
Expand Down
11 changes: 10 additions & 1 deletion src/Orchard.Web/Core/Title/Drivers/TitlePartDriver.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
using Orchard.ContentManagement;
using Orchard.ContentManagement.Drivers;
using Orchard.ContentManagement.Handlers;
using Orchard.Core.Common.Settings;
using Orchard.Core.Title.Models;
using Orchard.Core.Title.Settings;
using Orchard.Localization;

namespace Orchard.Core.Title.Drivers {
Expand Down Expand Up @@ -33,7 +35,14 @@ protected override DriverResult Editor(TitlePart part, dynamic shapeHelper) {
}

protected override DriverResult Editor(TitlePart part, IUpdateModel updater, dynamic shapeHelper) {
updater.TryUpdateModel(part, Prefix, null, null);
if (updater.TryUpdateModel(part, Prefix, null, null)){

var settings = part.Settings.GetModel<TitlePartSettings>();

if (settings.MaxLength > 0 && part.Title.Length > settings.MaxLength) {
updater.AddModelError("Title", T("The maximum allowed length for the title is {0}", settings.MaxLength));
}
}

return Editor(part, shapeHelper);
}
Expand Down
3 changes: 2 additions & 1 deletion src/Orchard.Web/Core/Title/Migrations.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using Orchard.ContentManagement.MetaData;
using Orchard.Core.Contents.Extensions;
using Orchard.Data.Migration;
using Orchard.Core.Title.Settings;

namespace Orchard.Core.Title {
public class Migrations : DataMigrationImpl {
Expand All @@ -9,7 +10,7 @@ public int Create() {
SchemaBuilder.CreateTable("TitlePartRecord",
table => table
.ContentPartVersionRecord()
.Column<string>("Title", column => column.WithLength(1024))
.Column<string>("Title", column => column.WithLength(TitlePartSettings.MaxTitleLength))
);

ContentDefinitionManager.AlterPartDefinition("TitlePart", builder => builder
Expand Down
19 changes: 19 additions & 0 deletions src/Orchard.Web/Core/Title/Settings/TitlePartSettings.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel;
using System.Linq;
using System.Web;

namespace Orchard.Core.Title.Settings {


public class TitlePartSettings {
// Whenever this constant is changed a new migration step must be created to update the length of the field on the DB
public const int MaxTitleLength = 1024;
[Range(0, MaxTitleLength)]
[DisplayName("Maximum Length")]
public int MaxLength {get; set;}

}
}
42 changes: 42 additions & 0 deletions src/Orchard.Web/Core/Title/Settings/TitlePartSettingsEvents.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using Orchard.ContentManagement;
using Orchard.ContentManagement.MetaData;
using Orchard.ContentManagement.MetaData.Builders;
using Orchard.ContentManagement.MetaData.Models;
using Orchard.ContentManagement.ViewModels;

namespace Orchard.Core.Title.Settings {
public class TitlePartSettingsEvents : ContentDefinitionEditorEventsBase {

public override IEnumerable<TemplateViewModel> TypePartEditor(ContentTypePartDefinition definition) {
if (definition.PartDefinition.Name != "TitlePart") {
yield break;
}

var settings = definition
.Settings
.GetModel<TitlePartSettings>()
?? new TitlePartSettings();

yield return DefinitionTemplate(settings);
}

public override IEnumerable<TemplateViewModel> TypePartEditorUpdate(ContentTypePartDefinitionBuilder builder, IUpdateModel updateModel) {

if (builder.Name != "TitlePart") {
yield break;
}

var model = new TitlePartSettings();

if (updateModel.TryUpdateModel(model, "TitlePartSettings", null, null)) {
builder.WithSetting("TitlePartSettings.MaxLength", model.MaxLength.ToString());

}
yield return DefinitionTemplate(model);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
@using Orchard.Core.Title.Settings;
@model TitlePartSettings
@{
var maxLength = TitlePartSettings.MaxTitleLength;
}

<fieldset>
<label for="@Html.FieldIdFor(m => m.MaxLength)">@T("Maximum length")</label>
@Html.EditorFor(m => m.MaxLength, new { htmlAttributes = new { min = 0, max = maxLength } })
<span class="hint">@T("Maximum length allowed for the title. Setting the value to 0 means the maximum allowed length is {0} characters.", maxLength)</span>
@Html.ValidationMessageFor(m => m.MaxLength)
</fieldset>
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
@model Orchard.Core.Title.Models.TitlePart
@using Orchard.Core.Title.Settings
@model Orchard.Core.Title.Models.TitlePart
@{
var maxLength = Model.Settings.GetModel<TitlePartSettings>().MaxLength > 0 ? Model.Settings.GetModel<TitlePartSettings>().MaxLength.ToString() : "";
}

<fieldset>
<label for="@Html.FieldIdFor(m => m.Title)" class="required">@T("Title")</label>
@Html.TextBoxFor(m => m.Title, new { @class = "text large", autofocus = "autofocus" })
<label for="@Html.FieldIdFor(m => m.Title)" class="required">@T("Title")</label>
@Html.TextBoxFor(m => m.Title, new { @class = "text large", autofocus = "autofocus", maxlength = maxLength })
<span class="hint">@T("You must provide a title for this content item")</span>
</fieldset>
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
using Orchard.ContentManagement.MetaData.Builders;
using Orchard.ContentManagement.MetaData.Models;
using Orchard.ContentManagement.ViewModels;
using Orchard.Taxonomies.Services;
using Orchard.Localization;
using Orchard.Taxonomies.Services;

namespace Orchard.Taxonomies.Settings {
public class TaxonomyFieldEditorEvents : ContentDefinitionEditorEventsBase {
Expand All @@ -20,8 +20,7 @@ public TaxonomyFieldEditorEvents(ITaxonomyService taxonomyService) {

public override IEnumerable<TemplateViewModel> PartFieldEditor(ContentPartFieldDefinition definition) {
if (definition.FieldDefinition.Name == "TaxonomyField") {
var model = definition.Settings.GetModel<TaxonomyFieldSettings>();
model.Taxonomies = _taxonomyService.GetTaxonomies();
var model = GetCurrentSettings(definition);
yield return DefinitionTemplate(model);
}
}
Expand All @@ -31,7 +30,8 @@ public override IEnumerable<TemplateViewModel> PartFieldEditorUpdate(ContentPart
yield break;
}

var model = new TaxonomyFieldSettings();
// Init this model preventively so if the TryUpdateModel doesn't execute correctly it doesn't cause an error
var model = GetCurrentSettings(builder.Current);

if (updateModel.TryUpdateModel(model, "TaxonomyFieldSettings", null, null)) {
builder
Expand All @@ -43,8 +43,15 @@ public override IEnumerable<TemplateViewModel> PartFieldEditorUpdate(ContentPart
.WithSetting("TaxonomyFieldSettings.AllowCustomTerms", model.AllowCustomTerms.ToString())
.WithSetting("TaxonomyFieldSettings.Hint", model.Hint);
}

yield return DefinitionTemplate(model);
}

private TaxonomyFieldSettings GetCurrentSettings(ContentPartFieldDefinition definition) {
var model = definition.Settings.GetModel<TaxonomyFieldSettings>();
model.Taxonomies = _taxonomyService.GetTaxonomies();
return model;
}

}
}

0 comments on commit 44bfa39

Please sign in to comment.