What you could very easily do is to implement IValidator class that will be triggered when a page/block is saved.
See the following example, but you might use any condition you like:
public class CarouselContentValidator : IValidate<StartPage>
{
IEnumerable<ValidationError> IValidate<StartPage>.Validate(StartPage instance)
{
if (instance.CarouselContent.AnyBlocks())
{
if (instance.CarouselContent.Contents.Any(
c => !c.GetOriginalType().IsAssignableFrom(typeof(TextOverImageBlock))))
{
var validationError = new ValidationError
{
ErrorMessage = LocalizationService.Current.GetString("/validation/carouselblocks"),
PropertyName = "CarouselContent"
};
return new[] { validationError };
}
}
return Enumerable.Empty<ValidationError>();
}
}
I get an error for GetOriginalType(). It says EPiServer.Core.IContent does not contain a definition for this. How can I fix this?
You can also implement ValidationAttribute (http://msdn.microsoft.com/en-us/library/system.componentmodel.dataannotations.validationattribute(v=vs.110).aspx) to handle the validation directly in the attribute whereever it's used. We will have a built in attribute to handle this in the 7.5 release.
I found this on nuget and it solves all of my problem with ContentAreas restrictions.
http://www.nuget.org/packages/OpenWaves.EPiServer.ExtendedContentAreaEditor/
"I get an error for GetOriginalType(). It says EPiServer.Core.IContent does not contain a definition for this. How can I fix this?"
I recently had the same problem after updating Episerver from the oldest possible version 7 to the latest. The solution was to add a "using EpiServer;" reference to the top of the document, as the method is an extension defined in EPiServer.RuntimeModelExtensions. I have no idea why the reference wasn't needed on the old codebase, but adding it after the update made it work again.
Ripped From the AvailablePageTypes type attribute:
[AttributeUsage(AttributeTargets.Property)]
public class AvailableContentTypesAttribute : ValidationAttribute
{
public System.Type[] Include
{
get;
set;
}
public System.Type[] Exclude
{
get;
set;
}
public override bool IsValid(object value)
{
if ((value != null) && !(value is ContentArea))
{
throw new ValidationException("AvailableContentTypesAttribute is intended only for use with ContentArea properties");
}
var contentArea = value as ContentArea;
var notAllowedcontentNames = new List<string>();
if (contentArea != null)
{
if (Include != null)
{
var notAllowedContent = contentArea.Contents.Where(x => !ContainsType(Include, x.GetType()));
if (notAllowedContent.Any())
{
notAllowedcontentNames.AddRange(notAllowedContent.Select(x => string.Format("{0} ({1})", x.Name, x.ContentLink.ID)));
}
}
if (Exclude != null)
{
var notAllowedContent = contentArea.Contents.Where(x => ContainsType(Exclude, x.GetType()));
if (notAllowedContent.Any())
{
notAllowedcontentNames.AddRange(notAllowedContent.Select(x => string.Format("{0} ({1})", x.Name, x.ContentLink.ID)));
}
}
}
if (notAllowedcontentNames.Any())
{
ErrorMessage = "contains invalid content items :";
foreach (var notAllowedcontentName in notAllowedcontentNames)
{
ErrorMessage += " " + notAllowedcontentName + ",";
}
ErrorMessage = ErrorMessage.TrimEnd(',');
return false;
}
return true;
}
private bool ContainsType(Type[] include, Type type)
{
return include.Any(inc => inc.IsAssignableFrom(type));
}
protected override System.ComponentModel.DataAnnotations.ValidationResult IsValid(object value, System.ComponentModel.DataAnnotations.ValidationContext validationContext)
{
var result = base.IsValid(value, validationContext);
if (result != null && !string.IsNullOrEmpty(result.ErrorMessage))
{
result.ErrorMessage = string.Format("{0} {1}", validationContext.DisplayName, ErrorMessage);
}
return result;
}
}
Usage:
Explicit inclusion:
[AvailableContentTypes(Include = new[] { typeof(SomeBlockType), typeof(SomePageType) })]
public virtual ContentArea ContentAreaProperty { get; set; }
Explicit exclusion:
[AvailableContentTypes(Exclude = new[] { typeof(NoAllowedBlockType), typeof(NotAllowedPageType) })]
public virtual ContentArea ContentAreaProperty { get; set; }
Prevents the ContentArea container from saving until only the correct types are included.
regards,
Danny
I'm having a issue restricting what kind of Block to be inserted in a ContentArea. What I want is that the SliderBlock's ContentArea property can only have insertion of a SlideItemBlock.
My block classes:
Or is this the wrong way to achive what I'm trying to restrict for the editor to not drag and drop wrong block types?
As of now, I can create a SliderBlock and insert a SlideItemBlocks in it. If I then insert the created SliderBlock in a new SliderBlock I get a forever and ever loop and It breaks the site. This is what I'm trying to control.