Thumbnail for image properties in Episerver

This article was migrated from an older iteration of our website, and it could deviate in design and functionality.


In this example we replace the default editor for image properties in Episerver to display a thumbnail of the selected image, but a similar approach could be used to replace the editor for any property type or UI hint.

Estimated read time : 3 minutes

Jump to

Create the custom editor dojo widget

First, let's create a new JavaScript file for our custom editor:

Make sure you have a dojo namespace mapped in module.config in your site root:

<?xml version="1.0" encoding="utf-8"?>
<module> 
    <dojo>
      <paths>
          <!-- Add a default namespace mapping for ~/ClientResources to the dojo loader configuration -->
          <add name="tedgustaf" path="" />
      </paths>
    </dojo>  
</module>

Next, add the custom editor code to the ImageContentSelector.js file:

define([
    "dojo/_base/declare",
    "dojo/dom-style",
    "dojo/aspect",

    "epi-cms/widget/ContentSelector"
],

function (
    declare,
    domStyle,
    aspect,

    ContentSelector
) {
    return declare([ContentSelector], {

        thumbnail: null,

        content: null,

        constructor: function() {
            this.inherited(arguments);

            // List for when the previewUrl property is set through the inherited _setValueAndFireOnChange method
            aspect.after(this, "set", function (name, value) {
                if (name === 'previewUrl' && value) {
                    this.updateThumbnail();
                }

                // No need to return - set method does not return anything
            }, true);

            // Create thumbnail element
            this.thumbnail = dojo.create("img");

            domStyle.set(this.thumbnail, 'borderBottom', '1px solid #929ba4');

            domStyle.set(this.thumbnail, 'display', 'none');
        },

        postCreate: function () {

            this.inherited(arguments);

            dojo.place(this.thumbnail, this.displayNode, "first");
        },
       
        _updateDisplayNode: function (content) {

            // Inherited from _SelectorBase through ContentSelector

            this.inherited(arguments);

            this.content = content;

            this.updateThumbnail();
        },

        updateThumbnail: function () {

            var content = this.content;

            var thumbnail = this.thumbnail;

            var clearThumbnail = function () {
                dojo.attr(thumbnail, 'src', '');
                domStyle.set(thumbnail, 'display', 'none');
            }

            if (content && thumbnail) {
                if (content.previewUrl && content.publicUrl) {

                    var previewUrlWithScaling = content.previewUrl;

                    var fileName = content.publicUrl.substr(content.publicUrl.lastIndexOf("/") + 1);

                    var fileExtension;

                    var indexOfLastDot = fileName.lastIndexOf('.');

                    if (indexOfLastDot != -1)
                    {
                        fileExtension = fileName.substring(indexOfLastDot + 1);
                    }

                    if (!fileExtension) {

                        var previewUrlSuffix = ',,' + content.contentLink;

                        var endOfFileNamePosition = content.previewUrl.lastIndexOf(previewUrlSuffix);

                        if (endOfFileNamePosition != -1) {

                            // Assume .jpg extension if no file extension in URL
                            previewUrlWithScaling = content.previewUrl.substring(0, endOfFileNamePosition) + '.jpg' + content.previewUrl.substring(endOfFileNamePosition);
                        }
                    }

                    previewUrlWithScaling += '&width=195';

                    dojo.attr(thumbnail, 'src', previewUrlWithScaling);
                    domStyle.set(thumbnail, 'display', '');
                }
                else {
                    clearThumbnail();
                }
            } else {
                clearThumbnail();
            }
        }
    });
});

Replace the default editor for image properties

We want our custom editor to be used for all image properties, i.e. ContentReference properties with a UI hint of UIHint.Image.

We do this by adding an editor descriptor class for UIHint.Image like so:

/// <summary>
/// Replaces the default editor for image properties
/// </summary>
[EditorDescriptorRegistration(TargetType = typeof(ContentReference), UIHint = UIHint.Image)]
public class ImageEditorDescriptor : EditorDescriptor
{
    public override void ModifyMetadata(ExtendedMetadata metadata, IEnumerable<Attribute> attributes)
    {
        base.ModifyMetadata(metadata, attributes);

        metadata.ClientEditingClass = "tedgustaf.editors.ImageContentSelector";
    }
}

This sets the editor widget to our custom editor for all properties of type ContentReference that have a UIHint of UIHint.Image.

Some things to note about dojo namespaces in Episerver

Since our widget is in a file called ImageContentSelector.js in the /ClientResources/Editors folder, we can now reference our editor, i.e. dojo class, like: tedgustaf.editors.ImageContentSelector (note that the namespace must be lower-case in dojo).

This is because the root namespace ("tedgustaf") is mapped to the ClientResources folder in module.config. This means a reference like tedgustaf.somethingelse.ClassName will resolve to /ClientResources/SomethingElse/ClassName.js.

The finished result

Final note on image resizing

The editor code is based on the assumption that an image resizer is present. In our case we use Image Resizer, which allows the thumbnail to be generated by simply adding a query string parameter to the preview URL.