In some scenarios we would like to disable creating new blocks functionality on Content Areas. Then editors will add only existing items using drag and drop functionality. We could implement one of few solutions to meet this requirement. It can be EditorDescriptor with client widget or quick hack enclosed in 10 lines of backend code.
By default Content Area editor displays “create a new block” link at the bottom.
Content Area property use “epi-cms/contentediting/editors/ContentAreaEditor” widget as Edit Mode editor. The widget has isCreateLinkVisible method responsible managing for action link visibility.
1 2 3 4 5 6 7 8 9 10 |
//... isCreateLinkVisible: function () { // summary: // Overridden mixin class, depend on currentMode will show/not create link // tags: // protected return this.model.canCreateBlock(this.allowedTypes, this.restrictedTypes); }, //... |
The method is marked as protected, so it can be safety overridden.
Quick solution
It’s possible to replace isCreateLinkVisible method in backed code with just few lines of code. We need to create attribute that implements IMetadataAware interface. In OnMetadataCreated method we set “isCreateLinkVisible” key for EditorConfiguration dictionary. The value will be JavaScript function which simply return false value. By default value will be converted to string. To ensure that it will be serialized as function we will use JRaw class.
1 2 3 4 5 6 7 8 9 10 11 12 13 |
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false)] public class OnlyDndAttribute : Attribute, IMetadataAware { public void OnMetadataCreated(ModelMetadata metadata) { var extendedMetadata = metadata as ExtendedMetadata; if (extendedMetadata == null) { return; } extendedMetadata.EditorConfiguration["isCreateLinkVisible"] = new JRaw("function() { return false; }"); } } |
Now using the OnlyDnd attribute on property we will change the editor behavior.
1 2 3 4 5 |
public class StandardPage : SitePageData { [OnlyDnd] public virtual ContentArea MainContentArea { get; set; } } |
This solution is a trick, because JSON object should contains only data and functions are not allowed.
Implementing new editor
If we don’t want to pass functions in JSON properties we could prepare new widget. It will extends ContentAreaEditor and override isCreateLinkVisible method.
In module.config we only register new path to the scripts.
1 2 3 4 5 6 7 8 9 |
<?xml version="1.0" encoding="utf-8" ?> <module> <dojo> <paths> <add name="contentAreaWithDndOnly" path="scripts" /> </paths> </dojo> </module> |
Inside widget code we override “isCreateLinkVisible” method:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
define([ "dojo/_base/declare", "epi-cms/contentediting/editors/ContentAreaEditor" ], function ( declare, _ContentAreaEditor ) { return declare([_ContentAreaEditor], { isCreateLinkVisible: function() { return false; } }); }); |
To use new widget we set ClientEditor attribute on Content Area property.
1 2 3 4 5 |
public class StandardPage : SitePageData { [ClientEditor(ClientEditingClass = "contentAreaWithDndOnly.contentAreaEditor")] public virtual ContentArea MainContentArea { get; set; } } |
This version is more elegant. It’s a standard way of extending EPiServer functionality.
Implementing editor descriptor
If we have more than one ContentArea property with hidden action link, then we could prepare new Editor Descriptor. The Editor Descriptor will inherit from ContentAreaEditorDescriptor and set the widget class to “contentAreaWithDndOnly/contentAreaEditor”.
1 2 3 4 5 6 7 8 9 10 |
[EditorDescriptorRegistration(TargetType = typeof (ContentArea), UIHint = UIHint)] public class OnlyDndContentAreaEditorDescriptor : ContentAreaEditorDescriptor { public const string UIHint = "OnlyDndContentArea"; public OnlyDndContentAreaEditorDescriptor() { this.ClientEditingClass = "contentAreaWithDndOnly/contentAreaEditor"; } } |
Then we could replace “contentAreaWithDndOnly.contentAreaEditor” constant used on property with Editor Descriptor UIHint.
1 2 3 4 5 |
public class StandardPage : SitePageData { [UIHint(OnlyDndContentAreaEditorDescriptor.UIHint)] public virtual ContentArea MainContentArea { get; set; } } |