In any reasonable sized EPiServer installation its not uncommon that there are a lot of page types available when creating a new page. Often there are a bewildering array of page names/descriptions so I wanted to give editors a visual reference on the content they are creating. I decided to create a simple enhancement to the standard "Create New" screen in EPiServer which would allow users to see an image of the page before they create it.

This would achieved with a thumbnail next to the name and description as shown below:

On clicking the image a larger preview window would appear which would allow users to create a new page from there: 

Build

The first thing we need to do is override the default "create new" functionality. Please see my other blog post about customising the EPiServer UI on how to achieve this. Now we have a editable copy of the create new page that we can amend to add the enhancement we want.

Now we need to add a thumbnail and preview URL for each page type. This is achieved by a simple trick, add two properties to the page called "SysThumbNailURL" and "SysPreviewURL" of type String (<=255). Don't show them in edit mode and give them a default value of the URL to the appropriate thumbnail or preview images for the page type. This allows us to access the default value as if it were meta data for the page type. An example showing "SysThumbNailURL" is shown below:

Next we need to add the overlay functionality. For this I used thickbox.js, but any javascript gallery will do. Please see ThickBox 3.1 for details.

Amend the create new pages as follows (EPiServer 6), which:

  • Adds the preview column
  • Gets the preview and thumbnail URLs
  • Adds the necessary css and javascript for adding ThickBox to the page

CreateNew.aspx

<%@ Page Language="c#" Codebehind="NewPage.aspx.cs" 
    AutoEventWireup="False" 
    Inherits="EPiServer.Templates.UICustomisations.CMS.Edit.NewPage" 
    MasterPageFile="../MasterPages/EPiServerUI.Master" Title="NewPage" %>
 
<asp:Content ID="Content2" ContentPlaceHolderID="MainRegion" runat="server">
 
<script type='text/javascript'>
     

            <!--

            function onNavigate(newPageLink)

            {

                return -1;

            }

            function onCommand(newCommand)

            {

                return -1;

           }

           // -->

 
</script>
    <div class="epitoolbuttonrow">
        <EPiServerUI:ToolButton id="Cancel" OnClick="Cancel_Click"  runat="server" Text="<%$ Resources: EPiServer, button.cancel %>" ToolTip="<%$ Resources: EPiServer, button.cancel %>" SkinID="Cancel" />
    </div>
 
    <asp:DataGrid ID="PageTypeList" AutoGenerateColumns="false" runat="server" OnDataBinding="SetHeaders"
        UseAccessibleHeader="True">
        <Columns>
            <asp:BoundColumn DataField="Name">
                <ItemStyle></ItemStyle>
            </asp:BoundColumn>
            <asp:BoundColumn DataField="Description">
                <ItemStyle></ItemStyle>
            </asp:BoundColumn>
            <asp:TemplateColumn>
                <ItemTemplate>
                    <asp:Literal ID="previewLink" runat="server" />
                </ItemTemplate>
            </asp:TemplateColumn>
        </Columns>
    </asp:DataGrid>
 
</asp:Content>

CreateNew.cs

using System;
using System.Data;
using System.Linq;
using System.Web.UI.WebControls;
using EPiServer.Core;
using EPiServer.DataAccess;
using EPiServer.UI;
using EPiServer.UI.WebControls;
using EPiServer.Web.PageExtensions;
using EPiServer.DataAbstraction;
using System.Collections.Generic;
 
namespace EPiServer.Templates.UICustomisations.CMS.Edit
{
    public class NewPage : SystemPageBase
    {
        // Fields
        private string _mode;
        protected ToolButton Cancel;
        protected DataGrid PageTypeList;
 
        // Methods
        public NewPage()
            : base(0, SiteRedirect.OptionFlag)
        {
        }
 
        protected void Cancel_Click(object sender, EventArgs e)
        {
            if ((this._mode == "simpleeditmode") || (this._mode == "createpage"))
            {
                base.RedirectToViewMode(this.CurrentPage.LinkURL);
            }
            else
            {
                base.Response.Redirect("EditPanel.aspx?id=" + this.CurrentPage.PageLink.ToString());
            }
        }
 
        protected virtual void HandleRedirect(string url)
        {
            base.Response.Redirect(url);
        }
 
        protected override void OnLoad(EventArgs e)
        {
            base.OnLoad(e);
            if (base.Request.Params["mode"] != null)
            {
                this._mode = base.Request.Params["mode"].ToLower();
            }
            if (!base.IsPostBack)
            {
                PageType type = PageType.Load(this.CurrentPage.PageTypeID);
                IEnumerable<PageType> allPageTypes = PageType.List();
                IList<PageType> source = type.FilterAllowedChildTypes(allPageTypes, base.User);
                if (source.Count == 1)
                {
                    this.HandleRedirect(string.Format("EditPanel.aspx?parent=" + this.CurrentPageLink.ToString() + "&type={0}&mode=" + base.Request.QueryString["mode"], source[0].ID));
                }
                var enumerable2 = source.Select(delegate(PageType pt)
                {
                    return new { ID = pt.ID, Name = LanguageManager.Instance.TranslateFallback(string.Format("/pagetypes/pagetype[@name='{0}']/name", pt.Name), pt.Name), Description = LanguageManager.Instance.TranslateFallback(string.Format("/pagetypes/pagetype[@name='{0}']/description", pt.Name), pt.Description) };
                });
                HyperLinkColumn column = new HyperLinkColumn();
                column.DataNavigateUrlFormatString = "EditPanel.aspx?parent=" + this.CurrentPageLink.ToString() + "&type={0}&mode=" + base.Request.QueryString["mode"] + ((base.Request.QueryString["epslanguage"] == null) ? "" : ("&epslanguage=" + base.Request.QueryString["epslanguage"]));
                column.DataNavigateUrlField = "ID";
                column.Text = base.Translate("/button/create");
                this.PageTypeList.Columns.AddAt(0, column);
                this.PageTypeList.DataSource = enumerable2;
                this.PageTypeList.ItemDataBound += new DataGridItemEventHandler(PageTypeList_ItemDataBound);
                this.PageTypeList.DataBind();
 
                Literal css = new Literal();
                css.Text = "<link rel=\"stylesheet\" href=\"" + ResolveUrl("~/Templates/UICustomisations/CMS/css/Thickbox.css") + "\" type=\"text/css\" media=\"screen\" />";
                this.Header.Controls.Add(css);
                this.ClientScript.RegisterClientScriptInclude("jQuery", "http://ajax.microsoft.com/ajax/jquery/jquery-1.3.2.js");
                this.ClientScript.RegisterClientScriptInclude("thickBoxJS", ResolveUrl("~/Templates/UICustomisations/CMS/js/thickbox.js"));
            }
        }
 
        protected void PageTypeList_ItemDataBound(object sender, DataGridItemEventArgs e)
        {
            if (e.Item.ItemType == ListItemType.Item || e.Item.ItemType == ListItemType.AlternatingItem)
            {
                Literal previewLink = (Literal)e.Item.FindControl("previewLink");
 
                //See if we have a preview URL
                string createNewPageURL = ((HyperLink)((TableRow)(e.Item)).Cells[0].Controls[0]).NavigateUrl;
                var dataItem = Cast(e.Item.DataItem, new { ID = 0, Name = "", Description = ""});
                int pageTypeID = dataItem.ID;
                previewLink.Text = this.GetPreviewLink(
                                        pageTypeID,
                                        dataItem.Description,
                                        "<a href=\'" + createNewPageURL + "\'>Create</a>");
            }
        }
 
        /// <summary>
        /// Work around when using anonymous types
        /// </summary>
        private T Cast<T>(object obj, T type)
        {
            return (T)obj;
        }
 
        protected string GetPreviewLink(int pageTypeID, string pageDescription, string createLink)
        {
 
            string thumbURL = string.Empty;
            string previewURL = string.Empty;
 
            //Retrieve the page properties and look for the thumbnail and preview URLs
            PageType pageDef = PageType.Load(pageTypeID);
            foreach (PageDefinition prop in pageDef.Definitions)
            {
                if (prop.Name == "SysThumbNailURL")
                {
                    thumbURL = ResolveUrl(prop.DefaultValue);
                }
                if (prop.Name == "SysPreviewURL")
                {
                    previewURL = ResolveUrl(prop.DefaultValue);
                }
            }
 
            if (thumbURL != string.Empty && previewURL != string.Empty)
            {
                return string.Format("<a href=\"{0}\" title=\"{1}\" class=\"thickbox\" rel=\"gallery\"><img src=\"{2}\" alt=\"Template preview\"/></a>",
                            previewURL,
                            createLink + " - " + pageDescription,
                            thumbURL);
            }
            else
            {
                return string.Empty;
            }
        }
        protected override void OnPreRender(EventArgs e)
        {
            base.OnPreRender(e);
        }
 
        protected void SetHeaders(object sender, EventArgs e)
        {
            this.PageTypeList.Columns[1].HeaderText = base.Translate("/admin/editpagetypebase/namecaption");
            this.PageTypeList.Columns[2].HeaderText = base.Translate("/admin/editpagetypebase/descriptioncaption");
            this.PageTypeList.Columns[3].HeaderText = LanguageManager.Instance.TranslateFallback("/admin/editpagetypebase/pagepreview", "Preview (click to enlarge)");
        }
    }
 
}

Make config changes to the episerver.config (EPiServer CMS 6) or web.config (EPiServer CMS 5) file as follows:

<virtualPathMappings>
  <add url="~/episerver/CMS/edit/NewPage.aspx" 
       mappedUrl="~/Templates/UICustomisations/CMS/Edit/NewPage.aspx"/>
</virtualPathMappings>

You will also need to add a reference to the EPiServer.UI assembly in your project.

Viola our solution is built and out editors have nice visual references to the content that they are going to be creating.

Future enhancements

I allowed myself three hours to build this solution so there is a lot that could be done with it so I’d be interested to hear if anyone takes things further! My ideas so far are:

  • Automatically generate a thumbnail and preview image
  • Use the DDS to store the page type meta data instead of a non edit mode page property
  • Allow users to select thumbnails directly from the file manager

Downloads

Note: I had to tweak the thickbox.js file included in the package below as there is a bug in the version publically available.

EPiServer 5 R2

EPiServer 6


Comments