When adding a block to HTML editor it’s rendered as a DIV element with name of the block. After a while it could be hard to determinate from where the block was referenced. I improved block rendering by adding “Edit” link to the block element.
In current Episerver version there is only a name of a block:
With the improved block editing there is additional “edit” link:
Implementation
To add a link I had to extend ContentFragment class and override GetEditFormat method. This method is responsible for rendering block when editing HTML property in edit mode. In extended version, after block name, there is an anchor element with information about ContentLink.
1 2 3 4 5 6 7 8 9 10 |
// ... public new string GetEditFormat() { var editFormat = base.GetEditFormat(); editFormat = editFormat.Replace("</div>", "<a data-type=\"context-link\" data-contentlink=\"" + this.ContentLink.ToReferenceWithoutVersion() + "\">Edit</a></div>"); return editFormat; } // ... |
CustomContentFragment is created by extended version of ContentFragmentFactory (CustomContentFragmentFactory). Factory is replacing original ContentFragmentFactory using interceptor.
1 2 3 4 5 6 7 8 9 10 11 |
[ModuleDependency(typeof(EPiServer.Web.InitializationModule))] public class BlockEditingInitialization : IConfigurableModule { public void ConfigureContainer(ServiceConfigurationContext context) { context.Services.Intercept<ContentFragmentFactory>( (locator, fragmentParser) => new CustomContentFragmentFactory()); } // ... } |
I also had to add custom Xhtml EditorDescriptor (CustomXhtmlStringEditorDescriptor) and override client editors for On-Page edit mode and Forms Editing mode. EditorDescriptor is also responsible for generating block editing template. Template is used when dropping a block into HTML editor.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
[EditorDescriptorRegistration(TargetType = typeof(XhtmlString), EditorDescriptorBehavior = EditorDescriptorBehavior.OverrideDefault)] public class CustomXhtmlStringEditorDescriptor : XhtmlStringEditorDescriptor { public override void ModifyMetadata(EPiServer.Shell.ObjectEditing.ExtendedMetadata metadata, IEnumerable<Attribute> attributes) { this.EditorConfiguration["blockTemplate"] = GetBlockEditTemplate(); this.ClientEditingClass = "alloy/editors/xhtml/TinyMCEEditor"; base.ModifyMetadata(metadata, attributes); metadata.CustomEditorSettings["uiType"] = "alloy/editors/xhtml/TinyMCEInlineEditor"; } private string GetBlockEditTemplate() { var contentFragment = new CustomContentFragment(ServiceLocator.Current.GetInstance<IContentLoader>(), ServiceLocator.Current.GetInstance<IContextModeResolver>()) {ContentLink = ContentReference.RootPage}; var editFormat = contentFragment.GetEditFormat(); editFormat = editFormat.Replace("data-contentlink=\"1\"", "data-contentlink=\"{contentLink}\""); editFormat = editFormat.Replace("data-contentname=\"Root\"", "data-contentname=\"{name}\""); editFormat = editFormat.Replace(">Root<", ">{name}<"); return editFormat; } } |
Both client editors share same mixin (WithBlockEditMixin) which is responsible for handling block editing.
Below is the demo:
Source code is available on GitHub.