The Optimizely Content Management System (CMS) implementation is built on the MVC implementation but extends it with functionality and additional usage scenarios.
As with Visitor Group and MVC implementations, CMS uses metadata for the classes and properties to define rules for how you can edit an object, such as in the following example:
Humanoid` class has three properties. Two have attributes that describe validation rules when you edit the object. The `
Name` property is required, and the `
Age` property must be between **0** and **999** to be valid.
To create an editor for a `
Humanoid` object instance, MVC has built-in editors for primitive types and a convention-based system where you can place user controls within folders to add editors for a type. CMS also has built-in editors for primitive types. When CMS generates an editor for a type, it traverses the object graph until it finds a registered editor for a type.
For the example class, an editor is not registered for the `
Humanoid` type, so the object editor assembler checks the properties for the Humanoid class. Because the three properties are of primitive types that CMS has registered editors for, you get three editors for the properties of the class.
### Object editing metadata and EditorDescriptor
An intermediate layer contains metadata for how you should create the user interface. When CMS creates an editor for an object, it creates a metadata hierarchy that represents the editors for the object graph by extracting metadata from the object’s properties and applying global metadata handlers. A global metadata handler can extend or change metadata from the classes.
The following example shows how to implement a metadata handler to map which client-side widgets can edit a specific type.
The metadata handler inherits from `
EditorDescriptor`. This class has properties you can set and a base implementation that applies these settings to the `
metadata` object. The base implementation only sets the values if no setting was specified, so settings defined on the model override the generic settings defined in this class.
The class also has a `
ModifyMetadata` method that is called after the metadata is extracted from the classes’ attributes. To set custom settings not supported by the properties on `
EditorDescriptor`, you can override this method and access the `
metadata` object directly.
An editor descriptor is registered as a singleton instance so that any settings that are set up in the constructor apply for the application's life cycle. Use the `
ModifyMetadata` method to define settings that should be dynamic, such as user-specific settings or translations.
## Metadata handler registry
Apply a metadata handler to the metadata extracted from an object with the `
MetadataHandlerRegistry` class, which maps types with metadata handlers. In the previous example, you registered the metadata class using the `
EditorDescriptorRegistration` attribute. You also can add metadata handlers directly in an initialization module:
StringEditorDescriptor` is called each time you extract metadata for a property of the type string and the `
DateTimeEditorDescriptor` each time you extract a DateTime.
You also can add a metadata handler for a list of types:
## Metadata providers
Sometimes, you want to take over the generation of metadata for an entire class, such as implementing `
PageData` in CMS. When you edit a `
PageData` class, you should focus on editing the items in the `
Properties` collection that have information about the real data for the `
Another example could be that you are using a third-party assembly where you do not have an option to add metadata attributes. This is possible through registering a metadata handler that implements the `
IMetadataProvider` interface, which has two methods you need to implement: `
CreateMetadata` and `
CreateMetadata` is called for the top-level object, and `
GetMetadataForProperties` for the sub-properties.
The following example shows a class that implements the `
IMetadataProvider` interface for the `
Metadata extenders are called even for metadata extracted from a custom `
## Common attributes
The object editing system uses the following metadata attributes.
### .NET Attributes
|Display||ShortDisplayName||The name that is shown as a label.|
|Order||How this property is ordered compared to other properties.|
|GroupName||The identifier of the group that the property belongs to.|
|Editable||AllowEdit||If the property is read only. This attribute overrides the ReadOnly attribute if both the **Editable** and **ReadOnly **attributes are defined.|
|ReadOnly||IsReadOnly||If the property is read only.|
|Required||-||The property becomes required.|
|ScaffoldColumn||ShowForEdit||If the property is shown when editing.|
### Additional EPiServer attributes
|ClientEditor||ClientEditingClass||The Dojo widget class name|
|ClientEditingPackage||The Dojo package that is required to load the widget. This only is necessary if the required package differs from the widget name.|
|DefaultValue||The default value of the widget.|
|EditorConfiguration||Settings that are passed to the widget as configuration. For instance: **min** and **max **values for an integer.|
|LayoutClass||The widget class that is responsible for the layout for this object and its children.|
|GroupSettings||Name||The identifier that matches the **GroupName** for the property.|
|Title||Title can be used to display a title for the group in the widget.|
|ClientLayoutClass||The widget class for the group.|
## Validate according to the MVC style model
The CMS object editing framework supports MVC 3’s built-in annotation-based validators. The following example shows a `
Person` class, with three properties: `
YearOfBirth`, and `
The editor generated by the framework validates entered data as:
Name` – Should not be more than 50 characters long. It should not be left empty.
YearOfBirth` – Should be from 1900 to 2000.
In MVC, decorate the class with validation attributes like:
The object editing framework understands these validation attributes. Validation information is sent to the client editors. Because the framework tries to map MVC validation rules to the rules in Dojo, there is no further work needed to make validation work on the client side. In detail, the following widget settings are used:
required` – Set to true if the editing property is marked with `
constraints` – The min and max constraints used to tell the widget to do a range validation.
regEx` – Directly mapped to the pattern set by `
missingMessage` – The error message specified in `
invalidMessage` – A combination of the error messages specified by validation attributes rather than `
[Required]`, separated by new-line characters **(CR/LF)**.
For the example, the client widget's initial settings should look as follows:
### Limitations when using multiple validation attributes
There are limitations to validation when you use specific combinations of attributes, because several validation attributes use the regex field for the client widget. For example, if you specify the `
regEx` attribute and constraints settings using `
EditorConfiguration` property of the `
ClientEditor` attribute, you override the model validation rules. Therefore, you should specify validation information also. For example, for a property that looks like this:
Unfortunately, you will not get the expected validation. The widget you get is:
The conclusion is that the `
StringLength` and `
RegEx` attributes do not work together. This is because the framework translates both of them into the client’s `
regEx` setting. In this case, the `
RegEx` attribute takes higher priority. For example, if you do not want the **Email** address to be too long, you would write:
As the result, `
StringLength` is not processed. The correct way to do is to define length constraint in your regular expression pattern:
## Validate a custom widget
Although the widgets that inherit `
dijit.form.ValidationTextBox` already fit to model validations, you may write a custom widget from scratch. The following example shows the rules you must follow to have your widget work well with MVC model validations. In this example, create a widget that is used to edit a money amount. The value should be a ranged number, followed by a currency sign like $ or E. In the model class, validation information is set as follows:
Next, create a widget that inherits `
dijit.\_Widget` and renders an HTML input. The start-up skeleton to follow looks as follows:
When the widget is created, the framework tries to mix in validation properties. Therefore, define those in the widget as follows:
To ensure that validation properties are correctly set, override the `
When the containing form does validation, it looks into the child widgets for validate methods, whose return value indicate if it is valid. Then, use validation information properties to write your own validation logic:
Almost all of the **dijit.\*** widgets support on-the-fly validation. To do the same, listen to onChange event and call the validate method.