Tags: Bilder CMS11 Egenskaper Optimizely/Episerver

Image preview in Episerver all properties view

In Episerver CMS, properties may be added to Images. Images may be enriched with copyright information, descriptions, etc that are displayed together with the images on your website. Editing this kind of information would be more intuitive if we could see both the image and the properties at the same time! And why can’t we see how large the image is without downloading it? We can!

Just some small changes, and we can have this:

All properties view with image preview

One possible way, as it often is when trying to make Episerver more editor-friendly, is adding an EditorDescriptor. Figure out the details you want to present in All properties view, and populate metadata.EditorConfiguration with them. We will later use dojo to pick it up and display it to the user.

[EditorDescriptorRegistration(TargetType = typeof(string), UIHint = "imagepreview")]
public class ImagePreviewEditorDescriptor : EditorDescriptor
{
   public override void ModifyMetadata(ExtendedMetadata metadata, 
      IEnumerable<Attribute> attributes)
   {
      var contentDataMetadata = metadata as ContentDataMetadata;
      if (!(contentDataMetadata?.OwnerContent is ImageFile imageFile))
      {
         base.ModifyMetadata(metadata, attributes);
         return;
      }

      ClientEditingClass = "alloy/editors/ImagePreview";

      // File name
      metadata.EditorConfiguration.Add("fileName", imageFile.RouteSegment);

      // Url
      var urlResolver = ServiceLocator.Current.GetInstance<IUrlResolver>();
      var url = urlResolver.GetUrl(imageFile.ContentLink);
      metadata.EditorConfiguration.Add("fileUrl", url);

      metadata.DisplayName = "";
      base.ModifyMetadata(metadata, attributes);
   }
}

In the screenshot, I have added some new information.

I have not included the code for file size and dimensions, but Its just System.Drawing.Image.FromStream(imageFile.BinaryData.OpenRead()) and checking its properties. The ClientEditingClass points to a JavaScript file we will create next. In my example, alloy will have to match the name parameter of the configuration in module.config:

<dojo>
   <paths>
      <add name="alloy" path="Scripts" />
   </paths>
</dojo>

And then some JavaScript placed in the folder /ClientResources/Script/Editors:

define([
   "dojo/_base/declare",
   "dijit/_CssStateMixin",
   "dijit/_Widget",
   "dijit/_TemplatedMixin",
   "dijit/_WidgetsInTemplateMixin"
],
   function(
      declare,
      _CssStateMixin,
      _Widget,
      _TemplatedMixin,
      _WidgetsInTemplateMixin
   ) {
      return declare("alloy.editors.ImagePreview",
         [_Widget, _TemplatedMixin, _WidgetsInTemplateMixin, _CssStateMixin], {
         templateString:
            "<div>\
               <div class=\"imagePreviewHeading\">\
                  <strong data-dojo-attach-point=\"imageName\"></strong><br>\
               </div>\
               <div class=\"imagePreview\" data-dojo-attach-point=\"imageContainer\"></div>\
            </div>",

         postCreate: function() {
            this.inherited(arguments);
            this.imageName.innerHTML = this.fileName;
            this.imageContainer.style = "background-image: url('" + this.fileUrl + "');";
            this.imageContainer.style.backgroundImage = "url('" + this.fileUrl + "');";
         }
      });
   });

Then, finally some CSS placed in /ClientResources/Styles/ImagePreview.css

.imagePreviewHeading {
    margin: 0 -20px;
    margin-right: -16px;
    padding: 10px;
    text-align: center;
    background-color: #f0f0f2;
    border: 1px #dedede solid;
}

.imagePreview {
    height: 250px;
    padding-top: 10px;
    background-origin: content-box;
    background-position: center;
    background-repeat: no-repeat;
    background-size: contain;
}

The CSS-file does not get loaded until we add this to our beloved module.config:

<clientResources>
   <add name="epi-cms.widgets.base" path="Styles/ImagePreview.css" resourceType="Style" />
</clientResources>

Then finally, you may place the preview wherever you like, just place a property with a matching UIHint.

[UIHint("imagepreview")]
public virtual string ImagePreview { get; set; }