Exam Area: Content Area 5 – Content Models (25%)
Reference: https://docs.developers.optimizely.com/content-management-system/docs/property-editors
// Suggests the editor type in CMS UI
public class ArticlePage : PageData
{
// Built-in UIHint values
[UIHint(UIHint.Image)] // Image selector
public virtual ContentReference HeroImage { get; set; }
[UIHint(UIHint.Video)] // Video selector
public virtual ContentReference Video { get; set; }
[UIHint(UIHint.MediaFile)] // Any media selector
public virtual ContentReference Attachment { get; set; }
[UIHint(UIHint.Textarea)] // Multi-line text
public virtual string Description { get; set; }
[UIHint(UIHint.HtmlEditor)] // Full TinyMCE editor
public virtual string Content { get; set; }
[UIHint(UIHint.FloatNumber)] // Float input
public virtual double Price { get; set; }
[UIHint(UIHint.LongString)] // Long text (equivalent to textarea)
public virtual string Notes { get; set; }
}
// EditorDescriptor maps UIHint → Editor widget
[EditorDescriptorRegistration(
TargetType = typeof(string),
UIHint = "ColorPicker",
EditorDescriptorBehavior = EditorDescriptorBehavior.ExtendBase)]
public class ColorPickerEditorDescriptor : EditorDescriptor
{
public ColorPickerEditorDescriptor()
{
ClientEditingClass = "myApp.ColorPickerEditor"; // Dojo widget
}
public override void ModifyMetadata(
ExtendedMetadata metadata,
IEnumerable<Attribute> attributes)
{
base.ModifyMetadata(metadata, attributes);
// Add configuration for the editor
metadata.EditorConfiguration["defaultColor"] = "#ffffff";
}
}
// Usage
[UIHint("ColorPicker")]
public virtual string TextColor { get; set; }
// Settings interface
public interface IPropertySettings<T> where T : PropertyDataType
{
bool IsModified { get; }
void Reset();
}
// TinyMCE Settings Example
public class CustomTinyMceSettings : TinyMcePropertySettings
{
public override bool IsDefault => false;
public override string GetConfiguration()
{
return new TinyMceConfiguration()
.AddToolbarRow("bold italic underline | bullist numlist | link image")
.AddPlugin("paste")
.AddPlugin("image")
.Build();
}
}
// Usage
[Display(Name = "Restricted editor")]
[BackingType(typeof(PropertyXhtmlString))]
[Settings(typeof(CustomTinyMceSettings))]
public virtual XhtmlString SimplifiedEditor { get; set; }
// Single select dropdown
[SelectOne(SelectionFactoryType = typeof(ThemeSelectionFactory))]
[Display(Name = "Theme")]
public virtual string Theme { get; set; }
// Multi select checkboxes
[SelectMany(SelectionFactoryType = typeof(CategorySelectionFactory))]
[Display(Name = "Categories")]
public virtual string[] Categories { get; set; }
// Selection factory
public class ThemeSelectionFactory : ISelectionFactory
{
public IEnumerable<ISelectItem> GetSelections(ExtendedMetadata metadata)
{
return new[]
{
new SelectItem { Text = "Light", Value = "light" },
new SelectItem { Text = "Dark", Value = "dark" },
new SelectItem { Text = "Blue", Value = "blue" }
};
}
}
[AutoSuggestSelection(typeof(CountrySelectionFactory))]
public virtual string Country { get; set; }
public class CountrySelectionFactory : IAutoSuggestSelectionFactory
{
public IEnumerable<ISelectItem> GetSuggestions(string query, int count, ExtendedMetadata metadata)
{
return Countries.All
.Where(c => c.Name.StartsWith(query, StringComparison.OrdinalIgnoreCase))
.Take(count)
.Select(c => new SelectItem { Text = c.Name, Value = c.Code });
}
}
// Create custom tab
public static class CustomTabs
{
[GroupDefinition]
public const string Metadata = "Metadata";
[GroupDefinition]
public const string SEO = "SEO";
}
// Usage
[Display(GroupName = CustomTabs.SEO, Order = 100)]
public virtual string MetaDescription { get; set; }
[Display(GroupName = SystemTabNames.Content, Order = 10)] // Built-in tab
public virtual string Heading { get; set; }
[Display(GroupName = SystemTabNames.Settings, Order = 10)] // Settings tab
public virtual bool ShowInMenu { get; set; }
// Available tabs:
SystemTabNames.Content // Main content tab
SystemTabNames.Settings // Settings tab
SystemTabNames.Shortcut // Shortcut tab
// Map .NET type → CMS property type
[BackingType(typeof(PropertyXhtmlString))]
public virtual XhtmlString Body { get; set; }
[BackingType(typeof(PropertyLongString))]
public virtual string LongText { get; set; }
[BackingType(typeof(PropertyContentReference))]
public virtual ContentReference Link { get; set; }
[BackingType(typeof(PropertyContentArea))]
public virtual ContentArea MainArea { get; set; }
UIHint(UIHint.Image) do? (Specifies the image selector editor for a property)EditorDescriptor used for? (Maps a UIHint string to a client-side editor widget)[Settings(typeof(...))] used with? (TinyMCE and other editors that have settings)[SelectOne] differ from [SelectMany]? (Single dropdown vs multi-select checkboxes)[BackingType] attribute do? (Maps a .NET type to a CMS property type for correct serialization/storage)