Merge branch '1.9.x' into dev

Conflicts:
	README.md
	src/Orchard.Web/Modules/Orchard.Dashboards/Web.config
	src/Orchard.Web/Modules/Orchard.DynamicForms/Orchard.DynamicForms.csproj
	src/Orchard.Web/Modules/Orchard.DynamicForms/ValidationRules/Compare.cs
	src/Orchard.Web/Modules/Orchard.DynamicForms/ValidationRules/EmailAddress.cs
	src/Orchard.Web/Modules/Orchard.DynamicForms/ValidationRules/Mandatory.cs
	src/Orchard.Web/Modules/Orchard.DynamicForms/ValidationRules/OptionRequired.cs
	src/Orchard.Web/Modules/Orchard.DynamicForms/ValidationRules/RegularExpression.cs
	src/Orchard.Web/Modules/Orchard.DynamicForms/ValidationRules/Required.cs
	src/Orchard.Web/Modules/Orchard.DynamicForms/ValidationRules/StringLength.cs
This commit is contained in:
Sipke Schoorstra
2015-11-03 22:44:13 +01:00
18 changed files with 257 additions and 24 deletions

View File

@@ -4,7 +4,7 @@ Orchard is a free, open source, community-focused Content Management System buil
[![Join the chat at https://gitter.im/OrchardCMS/Orchard](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/OrchardCMS/Orchard?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
You can try it for free on [Dotnest.com](https://dotnest.com) or on Microsoft Azure by clicking on this button
You can try it for free on [DotNest.com](https://dotnest.com) or on Microsoft Azure by clicking on this button
[![Deploy to Azure](https://azuredeploy.net/deploybutton.png)](https://ms.portal.azure.com/#create/OutercurveFoundation.OrchardCMS.0.5.9)
@@ -20,26 +20,29 @@ Orchard is delivered under the [.NET Foundation](http://www.dotnetfoundation.org
Our mission is to empower our users and foster a dedicated and diverse community that builds the CMS that we all want to use.
There are many ways you can [contribute to Orchard](http://orchardproject.net/contribution): you can [fix bugs](https://github.com/OrchardCMS/Orchard/issues), contribute modules and themes to [our gallery](http://gallery.orchardproject.net/), [write documentation](https://github.com/OrchardCMS/OrchardDoc), [translate Orchard](http://orchardproject.net/localize), or answer questions [on our forums](http://orchard.codeplex.com/discussions) and [on Stack Overflow](http://stackoverflow.com/questions/tagged/orchardcms).
## Project Status
Orchard is currently in version 1.9.1. We invite participation by the developer community in shaping the projects direction, so that we can publicly validate our designs and development approach.
Our 1.9.1 release is available from our Downloads page, and is easy to [Install Orchard using the Web Platform Installer](http://www.orchardproject.net/docs/Installing-Orchard.ashx). We encourage interested developers to check out the source code on the Orchard Github site and get involved with the project.
Orchard is currently in version 1.9.2. We invite participation by the developer community in shaping the projects direction, so that we can publicly validate our designs and development approach.
Our 1.9.2 release is available from our Downloads page, and is easy to [Install Orchard using the Web Platform Installer](http://docs.orchardproject.net/Documentation/Installing-Orchard). We encourage interested developers to check out the source code on the Orchard Github site and get involved with the project.
* [Download the latest release](https://github.com/OrchardCMS/Orchard/releases)
* [Feature roadmap](http://www.orchardproject.net/docs/feature-roadmap.ashx)
* [Feature roadmap](http://docs.orchardproject.net/Documentation/feature-roadmap)
* [Docs and designs/specs](http://www.orchardproject.net/docs)
* [About us](http://www.orchardproject.net/about)
* [Contact us](mailto:ofeedbk@microsoft.com)
## How To Get Involved
We hope that by engaging with the community in the very early stages of the project that we will be able to shape Orchard into a valuable set of tools and applications for the community. The Orchard team is committed to open community participation and accepts code contributions today. We encourage community participation at all levels from general project feedback to bug fixes and patches.
We hope that by engaging with the community we will continue to shape Orchard into a valuable set of tools and applications. The Orchard team is committed to open community participation and accepts code contributions. We encourage community participation at all levels from general project feedback to bug fixes and patches.
There are many ways you can [contribute to Orchard](http://orchardproject.net/contribution):
* [Check out the code](https://github.com/OrchardCMS/Orchard)
* [Check out the docs](http://orchardproject.net/docs)
* [Write documentation](https://github.com/OrchardCMS/OrchardDoc)
* [Find and file a bug](https://github.com/OrchardCMS/Orchard/issues)
* [Propose a feature idea](http://orchard.uservoice.com)
* [Ask and answer questions](http://www.orchardproject.net/discussions)
* [Ask and answer questions in our forums](http://www.orchardproject.net/discussions) and [on Stack Overflow](http://stackoverflow.com/questions/tagged/orchardcms)
* [Participate in our gitter.im chatroom](https://gitter.im/OrchardCMS/Orchard)
* [Participate in forum discussions](http://orchard.codeplex.com/discussions)
* [Submit a patch](http://www.orchardproject.net/docs/Contributing-patches.ashx)
* [Submit a pull request](http://docs.orchardproject.net/Documentation/Contributing-patches)
* [Translate Orchard](http://orchardproject.net/localize)
* [Contribute modules and themes to our gallery](http://gallery.orchardproject.net/)
* [Send us feedback](mailto:ofeedbk@microsoft.com)

View File

@@ -23,19 +23,20 @@
<!-- Prompts for the database name and fills it into the database scripts -->
<parameter name="Database Name" description="Name of the database for Orchard." defaultValue="orchard" tags="SQL, dbName">
<parameterEntry type="TextFile" scope="install.sql" match="PlaceHolderForDb" />
</parameter>
<!-- Prompts for the database username and fills it into the database scripts.
The SQL tag indicates it is a parameter required for SQL, the DbUsername tag indicates this is a Db username -->
<parameter name="Database Username" description="User name to access you application database." defaultValue="orcharduser" tags="SQL, DbUsername">
<parameterEntry type="TextFile" scope="install.sql" match="PlaceHolderForUser" />
<parameterEntry type="TextFile" scope="createuser.sql" match="PlaceHolderForUser" />
<parameterEntry type="TextFile" scope="createlogin.sql" match="PlaceHolderForUser" />
</parameter>
<!-- Prompts for the database password and fills it into the database scripts.
The SQL tag indicates it is a parameter required for SQL, the DbUserPassword tag indicates this is a Db password -->
<parameter name="Database Password" description="Password for the Database Username." tags="New, Password, SQL, DbUserPassword">
<parameterEntry type="TextFile" scope="install.sql" match="PlaceHolderForPassword" />
<parameterEntry type="TextFile" scope="createlogin.sql" match="PlaceHolderForPassword" />
</parameter>
<!-- Prompts for the admin creds and uses it for the administrator connection string. This is used to create a login and assign permissions.

View File

@@ -0,0 +1,79 @@
using Orchard.DynamicForms.Elements;
using Orchard.Forms.Services;
using Orchard.Layouts.Framework.Drivers;
using Orchard.Layouts.Framework.Display;
using Orchard.Layouts.Helpers;
using Orchard.Tokens;
using DescribeContext = Orchard.Forms.Services.DescribeContext;
namespace Orchard.DynamicForms.Drivers {
public class UrlFieldElementDriver : FormsElementDriver<UrlField> {
private readonly ITokenizer _tokenizer;
public UrlFieldElementDriver(IFormManager formManager, ITokenizer tokenizer) : base(formManager) {
_tokenizer = tokenizer;
}
protected override EditorResult OnBuildEditor(UrlField element, ElementEditorContext context) {
var autoLabelEditor = BuildForm(context, "AutoLabel");
var webAddressFieldEditor = BuildForm(context, "UrlField");
var webAddressFieldValidation = BuildForm(context, "UrlFieldValidation", "Validation:10");
return Editor(context, autoLabelEditor, webAddressFieldEditor, webAddressFieldValidation);
}
protected override void DescribeForm(DescribeContext context) {
context.Form("UrlField", factory => {
var shape = (dynamic) factory;
var form = shape.Fieldset(
Id: "UrlField",
_Value: shape.Textbox(
Id: "Value",
Name: "Value",
Title: "Value",
Classes: new[] {"text", "medium", "tokenized"},
Description: T("The value of this URL field.")));
return form;
});
context.Form("UrlFieldValidation", factory => {
var shape = (dynamic) factory;
var form = shape.Fieldset(
Id: "UrlFieldValidation",
_IsRequired: shape.Checkbox(
Id: "IsRequired",
Name: "IsRequired",
Title: "Required",
Value: "true",
Description: T("Tick this checkbox to make this email field a required field.")),
_MaximumLength: shape.Textbox(
Id: "MaximumLength",
Name: "MaximumLength",
Title: "Maximum Length",
Classes: new[] {"text", "medium", "tokenized"},
Description: T("The maximum length allowed.")),
_CustomValidationMessage: shape.Textbox(
Id: "CustomValidationMessage",
Name: "CustomValidationMessage",
Title: "Custom Validation Message",
Classes: new[] {"text", "large", "tokenized"},
Description: T("Optionally provide a custom validation message.")),
_ShowValidationMessage: shape.Checkbox(
Id: "ShowValidationMessage",
Name: "ShowValidationMessage",
Title: "Show Validation Message",
Value: "true",
Description: T("Autogenerate a validation message when a validation error occurs for the current field. Alternatively, to control the placement of the validation message you can use the ValidationMessage element instead.")));
return form;
});
}
protected override void OnDisplaying(UrlField element, ElementDisplayingContext context) {
context.ElementShape.ProcessedName = _tokenizer.Replace(element.Name, context.GetTokenData());
context.ElementShape.ProcessedLabel = _tokenizer.Replace(element.Label, context.GetTokenData());
context.ElementShape.ProcessedValue = _tokenizer.Replace(element.RuntimeValue, context.GetTokenData());
}
}
}

View File

@@ -0,0 +1,9 @@
using Orchard.DynamicForms.Validators.Settings;
namespace Orchard.DynamicForms.Elements {
public class UrlField : LabeledFormElement {
public UrlFieldValidationSettings ValidationSettings {
get { return Data.GetModel<UrlFieldValidationSettings>(""); }
}
}
}

View File

@@ -169,7 +169,9 @@
<Compile Include="Bindings\InputFieldBindings.cs" />
<Compile Include="Bindings\TaxonomyFieldBindings.cs" />
<Compile Include="Drivers\FieldsetElementDriver.cs" />
<Compile Include="Drivers\UrlFieldElementDriver.cs" />
<Compile Include="Elements\Fieldset.cs" />
<Compile Include="Elements\UrlField.cs" />
<Compile Include="Bindings\NumericFieldBindings.cs" />
<Compile Include="Forms\AddModelErrorForm.cs" />
<Compile Include="Forms\SelectDynamicForms.cs" />
@@ -220,7 +222,9 @@
<Compile Include="ValidationRules\EmailAddress.cs" />
<Compile Include="ValidationRules\RegularExpression.cs" />
<Compile Include="ValidationRules\StringLength.cs" />
<Compile Include="ValidationRules\UrlAddress.cs" />
<Compile Include="Validators\QueryValidator.cs" />
<Compile Include="Validators\Settings\UrlFieldValidationSettings.cs" />
<Compile Include="Validators\TaxonomyValidator.cs" />
<Compile Include="Validators\EnumerationValidator.cs" />
<Compile Include="Validators\CheckBoxValidator.cs" />
@@ -273,6 +277,7 @@
<Compile Include="Validators\ReCaptchaValidator.cs" />
<Compile Include="Validators\TextAreaValidator.cs" />
<Compile Include="Validators\TextFieldValidator.cs" />
<Compile Include="Validators\UrlFieldValidator.cs" />
<Compile Include="ViewModels\FieldValidationSettings.cs" />
<Compile Include="ViewModels\FormBindingSettings.cs" />
<Compile Include="Helpers\ContentTypeDefinitionExtensions.cs" />
@@ -509,6 +514,12 @@
<ItemGroup>
<Content Include="Assets.json" />
</ItemGroup>
<ItemGroup>
<Content Include="Views\Elements\UrlField.cshtml" />
</ItemGroup>
<ItemGroup>
<Content Include="Views\Elements\UrlField.Design.cshtml" />
</ItemGroup>
<PropertyGroup>
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">10.0</VisualStudioVersion>
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>

View File

@@ -22,7 +22,9 @@ namespace Orchard.DynamicForms.ValidationRules {
}
private LocalizedString GetValidationMessage(ValidationContext context) {
return new LocalizedString(Tokenize(T(ErrorMessage.WithDefault(String.Format("{0} must match the value of {1}.", context.FieldName, TargetName))).ToString(), context));
return String.IsNullOrWhiteSpace(ErrorMessage)
? T("{0} must match the value of {1}.", context.FieldName, TargetName)
: T(ErrorMessage, context);
}
}
}

View File

@@ -28,7 +28,9 @@ namespace Orchard.DynamicForms.ValidationRules {
}
private LocalizedString GetValidationMessage(ValidationContext context) {
return new LocalizedString(Tokenize(T(ErrorMessage.WithDefault(String.Format("{0} is not a valid email address.", context.FieldName))).ToString(), context));
return String.IsNullOrWhiteSpace(ErrorMessage)
? T("{0} is not a valid email address.", context.FieldName)
: T(ErrorMessage);
}
}
}

View File

@@ -18,7 +18,9 @@ namespace Orchard.DynamicForms.ValidationRules {
}
private LocalizedString GetValidationMessage(ValidationContext context) {
return new LocalizedString(Tokenize(T(ErrorMessage.WithDefault(String.Format("{0} is a mandatory field.", context.FieldName))).ToString(), context));
return String.IsNullOrWhiteSpace(ErrorMessage)
? T("{0} is a mandatory field.", context.FieldName)
: T(ErrorMessage);
}
}
}

View File

@@ -18,7 +18,9 @@ namespace Orchard.DynamicForms.ValidationRules {
}
private LocalizedString GetValidationMessage(ValidationContext context) {
return new LocalizedString(Tokenize(T(ErrorMessage.WithDefault(String.Format("An option is required for {0}.", context.FieldName))).ToString(), context));
return String.IsNullOrWhiteSpace(ErrorMessage)
? T("An option is required for {0}.", context.FieldName)
: T(ErrorMessage, context);
}
}
}

View File

@@ -27,7 +27,9 @@ namespace Orchard.DynamicForms.ValidationRules {
}
private LocalizedString GetValidationMessage(ValidationContext context) {
return new LocalizedString(Tokenize(T(ErrorMessage.WithDefault(String.Format("{0} must match the following pattern: {1}.", context.FieldName, Pattern))).ToString(), context));
return String.IsNullOrWhiteSpace(ErrorMessage)
? T("{0} must match the following pattern: {1}.", context.FieldName, Pattern)
: T(ErrorMessage);
}
}
}

View File

@@ -18,7 +18,9 @@ namespace Orchard.DynamicForms.ValidationRules {
}
private LocalizedString GetValidationMessage(ValidationContext context) {
return new LocalizedString(Tokenize(T(ErrorMessage.WithDefault(String.Format("{0} is a required field.", context.FieldName))).ToString(), context));
return String.IsNullOrWhiteSpace(ErrorMessage)
? T("{0} is a required field.", context.FieldName)
: T(ErrorMessage);
}
}
}

View File

@@ -40,12 +40,12 @@ namespace Orchard.DynamicForms.ValidationRules {
}
private LocalizedString GetValidationMessage(ValidationContext context) {
if (!String.IsNullOrWhiteSpace(ErrorMessage))
return new LocalizedString(Tokenize(String.Format(T(ErrorMessage).ToString(), context.FieldName, Minimum, Maximum), context));
if(!String.IsNullOrWhiteSpace(ErrorMessage))
return T(ErrorMessage, context.FieldName, Minimum, Maximum);
if(Minimum != null && Maximum != null)
return T("{0} must be between {1} and {2} characters long.", context.FieldName, Minimum, Maximum);
else if (Minimum != null)
if (Minimum != null)
return T("{0} must be at least {1} characters long.", context.FieldName, Minimum);
return T("{0} must be at most {1} characters long.", context.FieldName, Maximum);

View File

@@ -0,0 +1,36 @@
using System;
using System.Text.RegularExpressions;
using Orchard.DynamicForms.Helpers;
using Orchard.DynamicForms.Services;
using Orchard.DynamicForms.Services.Models;
using Orchard.Localization;
namespace Orchard.DynamicForms.ValidationRules {
public class UrlAddress : ValidationRule {
public UrlAddress() {
RegexOptions = RegexOptions.Singleline | RegexOptions.IgnoreCase;
Pattern = @"^http(s)?://([\w-]+.)+[\w-]+(/[\w- ./?%&=])?$";
}
public string Pattern { get; set; }
public RegexOptions RegexOptions { get; set; }
public override void Validate(ValidateInputContext context) {
if (!Regex.IsMatch(context.AttemptedValue, Pattern, RegexOptions)) {
var message = GetValidationMessage(context);
context.ModelState.AddModelError(context.FieldName, message.Text);
}
}
public override void RegisterClientAttributes(RegisterClientValidationAttributesContext context) {
context.ClientAttributes["data-val-regex"] = GetValidationMessage(context).Text;
context.ClientAttributes["data-val-regex-pattern"] = Pattern;
}
private LocalizedString GetValidationMessage(ValidationContext context) {
return String.IsNullOrWhiteSpace(ErrorMessage)
? T("{0} is not a valid URL.", context.FieldName)
: T(ErrorMessage);
}
}
}

View File

@@ -0,0 +1,8 @@
using Orchard.DynamicForms.Services.Models;
namespace Orchard.DynamicForms.Validators.Settings {
public class UrlFieldValidationSettings : ValidationSettingsBase {
public bool? IsRequired { get; set; }
public int? MaximumLength { get; set; }
}
}

View File

@@ -0,0 +1,28 @@
using System.Collections.Generic;
using Orchard.DynamicForms.Elements;
using Orchard.DynamicForms.Services;
using Orchard.DynamicForms.ValidationRules;
namespace Orchard.DynamicForms.Validators {
public class UrlFieldValidator : ElementValidator<UrlField> {
private readonly IValidationRuleFactory _validationRuleFactory;
public UrlFieldValidator(IValidationRuleFactory validationRuleFactory) {
_validationRuleFactory = validationRuleFactory;
}
protected override IEnumerable<IValidationRule> GetValidationRules(UrlField element) {
var settings = element.ValidationSettings;
if (settings.IsRequired == true)
yield return _validationRuleFactory.Create<Required>(settings.CustomValidationMessage);
if (settings.MaximumLength != null) {
yield return _validationRuleFactory.Create<StringLength>(r => {
r.Maximum = settings.MaximumLength;
r.ErrorMessage = settings.CustomValidationMessage;
});
}
}
}
}

View File

@@ -0,0 +1,21 @@
@using Orchard.DynamicForms.Elements
@using Orchard.Layouts.Helpers
@{
var element = (UrlField)Model.Element;
var tagBuilder = TagBuilderExtensions.CreateElementTagBuilder(Model, "input");
tagBuilder.AddCssClass("text design");
tagBuilder.Attributes["type"] = "url";
tagBuilder.Attributes["value"] = element.Value;
tagBuilder.Attributes["name"] = element.Name;
}
@if (element.ShowLabel) {
<div>
<label for="@element.HtmlId">@element.Label</label>
@tagBuilder.ToHtmlString(TagRenderMode.SelfClosing)
</div>
}
else {
@tagBuilder.ToHtmlString(TagRenderMode.SelfClosing)
}

View File

@@ -0,0 +1,25 @@
@using Orchard.DisplayManagement.Shapes
@using Orchard.DynamicForms.Elements
@using Orchard.Layouts.Helpers
@{
var element = (UrlField)Model.Element;
var tagBuilder = (OrchardTagBuilder)TagBuilderExtensions.CreateElementTagBuilder(Model, "input");
tagBuilder.AddCssClass("text");
tagBuilder.Attributes["type"] = "url";
tagBuilder.Attributes["value"] = Model.ProcessedValue;
tagBuilder.Attributes["name"] = Model.ProcessedName;
tagBuilder.AddClientValidationAttributes((IDictionary<string, string>)Model.ClientValidationAttributes);
if (!ViewData.ModelState.IsValidField(Model.ProcessedName)) {
tagBuilder.AddCssClass("input-validation-error");
}
}
@if (element.ShowLabel) {
<label for="@element.HtmlId">@Model.ProcessedLabel</label>
}
@tagBuilder.ToHtmlString(TagRenderMode.SelfClosing)
@if (element.ValidationSettings.ShowValidationMessage == true) {
@Html.ValidationMessage((string)Model.ProcessedName)
}

View File

@@ -176,8 +176,8 @@
break;
case "save":
{
var frameDoc = self.frame.getDocument();
var form = frameDoc.find("form:first");
var frameWindow = self.frame.getWindow();
var form = frameWindow.$("form:first");
form.submit();
}
break;