Don't miss out Virtual Happy Hour this Friday (April 26).

Try our conversational search powered by Generative AI!

Preview of custom MediaData

Vote:
 

Hi,

I've done a custom IContent implementation that inherits from MediaData. How can I create a custom preview view for these objects?

This is what I have right now, and that's not working:

[TemplateDescriptor(
    AvailableWithoutTag = true,
    Inherited = true,
    Tags = new[] { RenderingTags.Preview })]
public partial class MyCustomPreview : PreviewPage, IRenderTemplate, IRenderTemplate
{
}

When I double click or chose Edit on an object it goes directly to All Properties View.

#114267
Dec 08, 2014 22:18
Vote:
 

Bump!

#114580
Dec 16, 2014 3:28
Vote:
 

Do your custom media have its own controller and a view? Because if it has'nt a view it will go to the all properties view.

I have a custom mediatype, ImageFile that inherits from a base class, like this  (public class ImageFile : MediaBase, IContentImage) . The base class (MediaBase) inherits from mediadata.

#115033
Jan 08, 2015 10:51
Vote:
 

So, I have two views; one for when the content is inside e.g. a content area and that works well, and then I have a http handler for the preview. The preview handler works great if I navigate to it "manually". However, it seems like something is missing in edit mode since this view is not loaded.

My custom route for edit mode:

RouteTable.Routes.MapContentRoute(
    name: "ArkenaMediaEdit",
    url: CmsHomePath + "/arkena/{language}/{medianodeedit}/{partial}/{action}",
    defaults: new { action = "index" },
    contentRootResolver: (s) => root.ContentLink);

And this is my view:

public class ArkenaPreviewHandler : IHttpHandler, IRenderTemplate<ArkenaVideo>, IRenderTemplate

My view renders a simple html page with embed code for the video and this view works if I navigate to it "manually".

I also have a route without the language node, since my media data doesn't support that:

RouteTable.Routes.MapContentRoute(
    name: "ArkenaMedia",
    url: "arkena/{node}/{partial}/{action}",
    defaults: new { action = "index" },
    contentRootResolver: (s) => root.ContentLink);
#115065
Edited, Jan 08, 2015 18:19
Vote:
 

... and CmsHomePath looks like this:

private static string CmsHomePath
{
    get
    {
        return Paths.ToResource("CMS", "Content").Substring(1);
    }
}
#115066
Edited, Jan 08, 2015 18:23
Vote:
 

Some futher investigation... http://domain.local/episerver/CMS/Content/arkena/en/categories/category-1/category-2/test-movie,,1585__providerKey?epieditmode=True doesn't work. But if I remove ",,1585__providerKey?epieditmode=True" from the address the content and my preview is loaded, so http://domain.local/episerver/CMS/Content/arkena/en/categories/category-1/category-2/test-movie works fine.

#116354
Jan 28, 2015 23:54
Vote:
 

Ok, seems like my route for viewing the content is unnecessary, the default one seems to work. But still, preview doesn't work, just getting "Preview is not available for this item." Makes me think there is something wrong with the view, but it's weird that it works for viewing the item.

#116355
Jan 29, 2015 0:20
Vote:
 

It could be that your preview template is defined as a partial template rather than a page template. You can try to explicitly define it as a page template by adding

TemplateTypeCategory=TemplateTypeCategories.WebFormsPage

to your TemplateDescriptorAttribute

#116359
Jan 29, 2015 9:19
Vote:
 

Can't edit my first post, but since then I've changed the render template to a HttpHandler. But I added TemplateTypeCategory to the TemplateDescriptor and tried with both WebForm and HttpHandler with no luck :(

    [TemplateDescriptor(
        TemplateTypeCategory = TemplateTypeCategories.HttpHandler)]
    public class ArkenaPreviewHandler : IHttpHandler, IRenderTemplate<ArkenaVideo>, IRenderTemplate
#116398
Jan 29, 2015 15:56
Vote:
 

Hi

If you try

[TemplateDescriptor(

Inherited = true,

TemplateTypeCategory = TemplateTypeCategories.MvcController, //Required as controllers for blocks are registered as MvcPartialController by default

Tags = new[] { RenderingTags.Preview, RenderingTags.Edit }, Default = true,

AvailableWithoutTag = false)]

publicclassMediaDataPreviewController : ActionControllerBase, IRenderTemplate<MediaData>

{

public ActionResult Index(MediaData currentBlock)

{

.....

}

}

It will trigger when you goto edit mode

#116446
Jan 30, 2015 8:14
Vote:
 

I am not sure if this helps but this is how our defualt ones for image looks like for preview:

[TemplateDescriptor(
        Inherited = true,
        AvailableWithoutTag = false,
        TagString = RenderingTags.Preview,
        TemplateTypeCategory = TemplateTypeCategories.HttpHandler
    )]
    public class ImagePreviewHandler : MediaPreviewHandlerBase, IRenderTemplate<IContentImage>
    {
    }

and for edit it looks like:

 [TemplateDescriptor(
        Inherited = true,
        AvailableWithoutTag = false,
        TagString = RenderingTags.Edit,
        TemplateTypeCategory = TemplateTypeCategories.MvcController
    )]
    public class ImageEditController : MediaEditController<IContentImage>

 

#116453
Jan 30, 2015 9:44
Vote:
 

@Anders, won't work since this is a handler and now a mcv controller.

@Johan, none of those template descriptors works.

If I remove my custom route for edit mode I get a 404 instead of a "No preview for this content" message. View mode still works without any custom routes. That's so weird, if view mode works, why is not that view loaded as a fallback in edit mode?

#116511
Jan 30, 2015 19:56
Vote:
 

As a reference, the YouTube provider registers custom routes https://github.com/episerver/YouTubeContentProvider/blob/master/EPiServer.Sample.YouTubeProvider/YouTubeInitializer.cs, to get the thumbnails to work and to get it to work without the language segment.

Can it be that I have a handler and not a view or webform, i.e. not partial rendering? But a handler is not partial? The reason for having a handlar is that it can be compiled and is easier to distribute.

This is my complete handler:

[TemplateDescriptor(
    Default = true,
    TemplateTypeCategory = TemplateTypeCategories.HttpHandler)]
public class ArkenaPreviewHandler : IHttpHandler, IRenderTemplate<ArkenaVideo>, IRenderTemplate
{
    public bool IsReusable
    {
        get { return true; }
    }

    public Injected<ArkenaSettingsRepository> SettingsRepository { get; set; }

    protected ArkenaSettings CurrentSettings
    {
        get
        {
            return this.SettingsRepository.Service.LoadSettings();
        }
    }

    public void ProcessRequest(HttpContext context)
    {
        var video = ServiceLocator.Current.GetInstance<ContentRouteHelper>().Content as ArkenaVideo;

        if (video != null)
        {
            context.Response.Write(string.Format(@"
                                <!DOCTYPE html>
                                <html>
                                        <head>
                                        <style>
                                            body {{
                                                margin: 0;
                                            }}

                                            #video-container object {{
                                                position: absolute;
                                                width: 100%;
                                                height: 100%;
                                            }}
                                        </style>
                                        <script>var Qbrick = Qbrick || {{}}; Qbrick.initializePublisher = false;</script>
                                        <script src=""//publisher.qbrick.com/Qbrick.Publisher.js""></script>
                                    </head>
                                    <body>
                                        <div id=""video-container""></div>
                                        <script>
                                            var params = {{
                                                mcid: ""{0}"",
                                                as: 0,
                                                width: 800,
                                                height: 460
                                            }};

                                            Qbrick.Publisher.create(document.getElementById(""video-container""), params);
                                    </script>
                                    </body>
                                </html>", video.ItemId + this.CurrentSettings.PlayerId));
        }
    }
}
#116513
Jan 30, 2015 20:26
Vote:
 

Sorry I did not realize that you had an own content proivder. Then you might need to add a custom route depending on your entry point. The reason the youtube provider registers a custom route is that it serves it's content from an own root outside the GlobalAssetsRoot (where media normally is stored). If the entry point is an existing folder under GlobalAssetsRoot then it's not necessary to create a custom route.

Regarding template selection there are events TemplateResolver.TemplateResolving and TemplateResolver.TemplateResolved that will be raised during template selection. You can assign a specific template in the event handler (in your case you could e.g. hook up to the "ing" event and see if the instance is of your type and tag is "edit" or "preview" and then assign your template to the event args). However I cant figure out why the ordinary selection does not work for you. Perhaps you can get some info if you attach event handlers for the events and put breakpoints in the event handlers and then debug and see the arguments that gets called when your content type is selected for edit/preview?

#116582
Feb 02, 2015 16:45
Vote:
 

Hi again,

So I've done some more debugging now. The template resolver is called numerous times, first with no tag, then with Edit and last with Preview. Every time my preview handlers is selected in the SelectedTemplate property. But even though, there is no preview in edit mode!

I actually got my preview to load now for these urls:

  • http://domain.local/episerver/CMS/Content/arkena/sv/categories/category-1/video,,1585__arkena?epieditmode=True

  • http://domain.local/episerver/CMS/Content/arkena/sv/categories/category-1/video,,1585__arkena?epieditmode=False

  • http://domain.local/arkena/sv/categories/category-1/video/

  • http://domain.local/arkena/categories/category-1/video/

Got that to work when I specified as much as I could in the TemplateDescriptor:

[TemplateDescriptor(
    AvailableWithoutTag = true,
    Default = true,
    Inherited = true,
    Tags = new[] { RenderingTags.Edit, RenderingTags.Preview },
    TemplateTypeCategory = TemplateTypeCategories.HttpHandler)]
#116584
Feb 02, 2015 20:09
Vote:
 

To answer your original question, media data does not have on-page edit as an available view. That is why you are taken directly to all properties edit. If you were to extend VideoData or ImageData instead of MediaData then on-page edit will become available and will also be the default view.

Alternatively, if you for some reason can't extend from them then you can add the following to the constructor on your UIDescriptor:

DefaultView = CmsViewNames.OnPageEditView;
DisabledViews = new string[] {};

This will override the settings that come from the UIDescriptor for MediaData and set the default view to on-page edit and make it so that no views are disabled.

#118257
Mar 03, 2015 12:26
Vote:
 

Thanks Ben! Removing the disabled views was what I was looking for. Maybe I could've inherited from VideoData in this case, but I also wanted to get the preview to work for PDFs as well.

#118276
Mar 03, 2015 19:14
Vote:
 

Ok, I spoke to soon. It worked great in my custom UI descriptor. But how can I change this for alreday registered descriptors? DisabledView's setter is protected...


I was trying to do something like this in an initializable module:

var type = typeof(DocumentFile); 
var registry = ServiceLocator.Current.GetInstance<UIDescriptorRegistry>();
var descriptors = registry.UIDescriptors.Where(d => type.IsAssignableFrom(d.ForType));

foreach (var descriptor in descriptors)
{
    descriptor.DisabledViews = new string[] { }; // won't work, since setter is protected
}


DocumentFile inherits from MediaData.

#118280
Mar 03, 2015 19:32
Vote:
 

Could you just set the disabled types on a UIDescriptor for DocumentFile? Otherwise you can create UIDescriptors for your content types which inherit from DocumentFile. But maybe I'm not understanding the scenario.

#118306
Mar 04, 2015 9:44
Vote:
 

Maybe it's me not getting the concept of the UI descriptors... I know there used to be a problem registering descriptors for types that already had one, and I'm not in control over the descriptor for that type. That's why I was trying to update the already registered one. But it's seem to work by register a new one and set DisabledViews in the constructor.

Thanks again.

#118357
Mar 04, 2015 18:59
This topic was created over six months ago and has been resolved. If you have a similar question, please create a new topic and refer to this one.
* You are NOT allowed to include any hyperlinks in the post because your account hasn't associated to your company. User profile should be updated.