Views: 13275
Number of votes: 8
Average rating:

Customizing the look and behavior in the UI for your content types

In EPiServer 7.5 we have done some additions that makes it possible to alter quite a few things regarding how your content types should look and behave in the EPiServer UI. This is done by adding something called a UI Descriptor which is responsible for instructing the EPiServer UI how you want instances of the given content type to behave. Lets start with a simple example taken from the Alloy sample project:

using EPiServer.Shell;
using EPiServer.Templates.Alloy.Models.Pages;
 
namespace EPiServer.Templates.Alloy.Business.UIDescriptors
{
    [UIDescriptorRegistration]
    public class ContainerPageUIDescriptor : UIDescriptor<ContainerPage>
    {
        public ContainerPageUIDescriptor()
            : base(ContentTypeCssClassNames.Container)
        {
            DefaultView = CmsViewNames.AllPropertiesView;
        }
    }
}

What the code above does is configuring the following settings for the type ContainerPage:

  • A custom css class used as an icon (this is used for the navigation tree as well as different listings, for instance recent items).
  • Defines that the default view for items of this type should be the “All properties” view.

In the example above we are using one of the built in css classes in EPiServer but there is nothing preventing you from adding your own classes/icons (see Stefan Torstenssons blog post about how to add custom styles to the EPiServer UI http://world.episerver.com/Blogs/Stefan-Torstensson/Dates/2012/12/Adding-a-new-device-to-the-view-resolution-drop-down/).

ContainerPageScreenShot

Image showing how container pages have a different icon compared to other pages.

Hint: You can use the technique above if you want to have the “All properties” view as the default view for some of your content types, for instance a content type where it makes no sense using on page editing.

Content blocks in Tiny MCE

Another thing you can configure is the desired behavior when you drag-and-drop an item to a html editor. The default behavior for pages is that a link to the page is inserted to the editor. For blocks however, a “content block” is created using the same technology as for content areas. The following screen shot shows how a block is inserted to a html editor:

DndBlock

 

When the property is rendered to the page it will render using a partial renderer, following the same rules as for a content area:

Rendered block

 

We can change the desired behavior for what happens when dropping an item to an editor by setting the EditorDropBehavior property in the UIDescriptor. Lets try adding a ui descriptor to the SitePageData base class that all pages in the Alloy template inherits from:

using EPiServer.Shell;
using EPiServer.Templates.Alloy.Models.Pages;
 
namespace EPiServer.Templates.Alloy.UIExtensions
{
    [UIDescriptorRegistration]
    public class SitePageUIDescriptor : UIDescriptor<SitePageData>, IEditorDropBehavior
    {
        public SitePageUIDescriptor()
        {
            EditorDropBehaviour = EditorDropBehavior.CreateContentBlock;
        }
 
        public EditorDropBehavior EditorDropBehaviour { get; set; }
    }
}

 

Now when a page is drag-and-dropped to the editor, a content block containing the page is created instead:

DndContainerPage

And this is rendered using a partial template, just as for the block:

RenderedBlockAndPage

The settings for content types are inherited so settings you define will affect all inhirited types unless there is a more specific setting defined for a sub type. We currently have no good way to alter the setting for built in EPiServer types (PageData, BlockData etc.) so if you want to change settings for all types for a given main type (all pages, all blocks etc.) I recomend using a base class in your template package as in the Alloy example.

Nice!

Here is how you change the default view for a product:

[UIDescriptorRegistration]
public class CatalogContentUiDescriptor : UIDescriptor
{
public CatalogContentUiDescriptor() : base()
{
DefaultView = CmsViewNames.OnPageEditView;

}
}

I'm trying to enable partial view for pages in TinyMCE. Is it possible to make use of Tags here to change rendering class (Used RenderingsTags on )?
I can only get it to work without tags.

@Sven: Do I understand you correctly that you want to add a tag on the html-property that will be used when determining which template to use for any content items inside of the html?

@Linus: Yes, that's correct. Simular/same function that is used on ContentAreas (tag to select correct template renderer).

I tried adding a tag to the property declaration and it works the same way as for content areas, that is: I can trigger another template for the partial rendering by setting a tag, for instance:



Ok. That's what I think I did in my test. I tried this during the episerver training course today (No more training days in this course, so test environment is gone now). I must have dona something wrong on my configuration of my template renderer. Good to know that it shoppa be possible. I'm satisfied with that so see my question as answered/solved :-)

When it comes to dropping Pages and Blocks, wouldn't it be nice to be able to have DisplayOptions on Content dragged to the TinyMCE-editor?

Also, having an option "None" would be nice.
As in "I never want to drop this content into a tinymce field"

Thanks for the feedback Alf. I'm forwarding the request for DisplayOptions to the PM:s since it's basically a new feature. For the none option, I checked the code and thought that it would be possible be defining EditorDropBehavior.Undefined. Unfortunately, 0 is currently being treated as undefined and we will fetch settings from a parent type. I have reported a bug for this: Bug #112099: TypeDescriptorManager does not support a value being 0

I can add that the bug mentioned above has been fixed and released so that it's now possible to have no effect when a specific item is dropped to an editor.

Ah, great stuff. Was just looking for this.

Combined with this: http://www.epinova.no/en/blog/arve-systad/dates/2014/7/custom-rendering-of-content-in-xhtmlstring-areas/ it makes for very powerful customization features "inline" in regular text areas. (Using it as a mix between a ContentArea and XhtmlArea, sortof).

Hello Guys,

We are developing a solution based on EPiServer 7.5 update 37, and were wondering..

Is there a way to limit the block types that can be dragged into a RichText area?
Is there a way to use displayOptions in blocks that are added into a RichText area?

Cheers!
- Wac

Hi!

There are two ways to prevents types being added to the editor. The first is the AllowedTypes attribute. This has some limitations but you can add a list of specific types or some built in base types like PageData, ContentFolder etc. There are also some work arounds to get support to add prevention logic based on your own base classes and interfaces:
http://world.episerver.com/Blogs/Linus-Ekstrom/Dates/2013/12/Restriction-of-content-types-in-properties/

The second way to prevent actions when dropping a specific type, mentioned previously in the comments, by setting EditorDropBehavior.Undefined for a UIDescriptor. This will not prevent the editor from dropping instances of the type to the editor, but nothing will happen when the item is dropped so this way you can prevent actions for an entire type regardless of property.

Regarding the display options, we do not currently support this but it's something that we have heard requests for a few times and it's something that we would like to add to get the functionality matching the content area.

Hey guys!

I've noticed that UIDescriptorRegistration only runs when a site is restarted and I wonder if you can trigger this by code somehow? Our editors wants to have the ability to chose to have either All Properties View by defailt or On-Page edit view by default. My thought was to have a group (for example AllProperteesEditView) and add those editors that want All properties view by default to that group so each time a user logs in you check wether that user is part of the AllProperties.EditView-group and show the appropiate edit view.

Hi Alexander.

As you mention, the UI Descriptors are treated as singleton objects that are created when the application starts. The means that there is currently no way of modifying them runtime without affecting all users. I tried finding a work around, like using the new keyword for the DefaultView property but that does not work. We have taken the feedback though so if this is something that we hear that there is a big need for, we might implement some way to do this going forward.

ps. If you really want to find a solution, you might get away with a real hacky solution like implementing a property with a getter that actually sets the value for the DefaultView property. The idea here is that your property is called when the object is serialized and sent to the client. This is to be considered as a hack and to be able to make this work you need to figure out and make sure that your property is serialized before the DefaultView which I'm not sure is even possible. Then you of course have potential, but probably unlikely, threading issues but that might not be a big issue in this case. ds.

Hi Linus!

Thanks for answering. It would be a really nice-to-have function if the editors themselves could choose what kind of edit-mode that should be default so if you could implement it in a future release that would be great! In the meantime we've informed our editors that they have the ability to switch every deploy (when we restart the site) if they want to toggle default mode.

Hi guys,

I've noticed that editing of a custom block breaks when a display template for XhtmlString is present. The issue is mentioned in the comments for https://www.epinova.no/en/blog/arve-systad/dates/2014/7/custom-rendering-of-content-in-xhtmlstring-areas/. Has anyone found a way around it withouth dropping the template? I tried using FullRefreshPropertiesMetaData though it was a long shot since the editing breaks in All properties view as well. The template doesn't do anything fancy: It renders the property using the EPiServer.Web.Mvc.Html.XhtmlStringExtensions.XhtmlString extension and potentially adds a wrapper div.

How can I code custom drop behavior if I could so?

See also my question.

@Jiri: I have answered your question in the other forum thread.

I have learned many language of CS to make the content better and also it’s UI. In this site of essay uk we know about the customizing the look and behavior of the UI and content types.

Please login to comment.