Pages

Showing posts with label EpiServer. Show all posts
Showing posts with label EpiServer. Show all posts

Thursday, January 14, 2010

Declaritively show content in EpiServer

Not sure if this is a new idea (I doubt it - very few things ever are). I'm a big fan of reducing the amount of display logic in code-behind, especially showing and hiding regions of the page dependant on content stored in the CMS. What I wanted was a custom control in which you could declare a list of EpiServer properties which would need to be not empty for the control to render. I bet you've done this kind of thing a thousand times with a standard <asp:placeholder ... /> and code-behind. Here's a self-contained custom control which takes away all your code-behind pain and mess and allows you to just write markup in your .aspx/.ascx:
public class EpiPlaceHolder : PlaceHolder
{
    protected override void OnInit(EventArgs e)
    {
        this.Load += new EventHandler(EpiPlaceHolder_Load);
        base.OnInit(e);
    }

    public string Property
    {
        get;
        set;
    }

    public bool ShowOnFalse
    {
        get;
        set;
    }

    public PageData CurrentPage
    {
        get;
        set;
    }

    void EpiPlaceHolder_Load(object sender, EventArgs e)
    {
        bool isVisible = false;

        if (CurrentPage == null)
        {
            CurrentPage = ((EPiServer.TemplatePage)Page).CurrentPage;
        }

        if (Property != null)
        {
            string propertyName = Property;

            if (propertyName.Contains(","))
            {
                string[] props = propertyName.Split(new char[] { ',' });

                foreach (string prop in props)
                {
                    isVisible = IsVisibleForProperty(prop);

                    if (!isVisible)
                    {
                        break;
                    }
                }
            }
            else
            {
                isVisible = IsVisibleForProperty(propertyName);
            }
        }

        Visible = (ShowOnFalse) ? !isVisible: isVisible;
    }

    private bool IsVisibleForProperty(string propertyName)
    {
        object currentProperty = CurrentPage[propertyName];

        bool isVis = false;
        if (currentProperty != null)
        {
            bool tryParseProperty = false;
            if (bool.TryParse(currentProperty.ToString(), out tryParseProperty))
            {
                isVis = tryParseProperty;
            }
            else
            {
                isVis = true;
            }
        }

        return isVis;
    }
}
Here's how to use it:
<pdp:EpiPlaceHolder ID="EpiPlaceHolder1" runat="server" Property="LeadImage">
    <EPiServer:Property ID="Property2" runat="server" PropertyName="LeadImage" />
</pdp:EpiPlaceHolder>

Thursday, October 22, 2009

More EpiServer extension methods

Here's another extension method for returning a normal EpiServer Url to a page from a LinkItem (from a PropertyLinkCollection).

public static class LinkItemExtensions
{
public static string ToExternal(this LinkItem item)
{
string externalUrl = item.Href;

PermanentLinkMapStore.TryToMapped(item.Href, out externalUrl);

return externalUrl;
}
}


I'm using the PermanentLinkMapStore following a read of this post.

I've been using it when binding a LinkItemCollection to a ListView like this:
PropertyLinkCollection linksProperty = CurrentPage.ToProperty("Links");

var links = from l in linksProperty.Links
select new
{
Href = l.ToExternal(),
Title = l.Title,
Text = l.Text,
Extension = Path.GetExtension(l.Href)
};

lvLinks.DataSource = links;
lvLinks.DataBind();

Wednesday, October 14, 2009

EpiServer Extension methods

Following on from my previous post I realised that the majority of the Extension methods that I use in everyday coding are EpiServer related.

Here are some really useful ones:


/// <summary>
/// Gets the children.
/// </summary>
/// <param name="page">The page.</param>
/// <returns></returns>
public static PageDataCollection GetChildren(this PageData page)
{
PageDataCollection children = new PageDataCollection();

if (page.PageLink != null && page.PageLink.ID > 0)
{
children = DataFactory.Instance.GetChildren(page.PageLink);

FilterPublished publishedDateFilter = new FilterPublished(PagePublishedStatus.Published);
FilterSort indexSorter = new EPiServer.Filters.FilterSort(FilterSortOrder.Index);

publishedDateFilter.Filter(children);
indexSorter.Sort(children);
}

return children;
}

/// <summary>
/// Gets the external URL.
/// </summary>
/// <param name="page">The page.</param>
/// <returns></returns>
public static string GetExternalUrl(this PageData page)
{
string result = String.Empty;

if (page != null)
{
UrlBuilder builder = new UrlBuilder(page.LinkURL);

EPiServer.Global.UrlRewriteProvider.ConvertToExternal(builder, page, Encoding.UTF8);

result = builder.ToString();
}

return result;
}


/// <summary>
/// Returns a concrete PropertyData (or child class)
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="page">The page.</param>
/// <param name="propertyName">Name of the property.</param>
/// <returns></returns>
public static T ToProperty<T>(this PageData page, string propertyName) where T : PropertyData
{
return page.Property[propertyName] as T;
}

/// <summary>
/// Returns a PageData property or string.Empty if null
/// </summary>
/// <param name="page">The page.</param>
/// <param name="propertyName">Name of the property.</param>
/// <returns></returns>
public static string SafeProperty(this PageData page, string propertyName)
{
return (page.HasProperty(propertyName)) ? page[propertyName].ToString() : string.Empty;
}


/// <summary>
/// Gets the page for a Pagereference.
/// </summary>
/// <param name="pageRef">The Pagereference.</param>
/// <returns></returns>
public static PageData GetPage(this PageReference pageRef)
{
return DataFactory.Instance.GetPage(pageRef);
}

Some useful Extensions methods

Extension methods have been around a while now and I like them more every day. Oh I know they are just aliased static methods, but they are convenient for small common situations where it seems like the framework developers missed something out.

Here's a few of my that I find useful:

NameValueCollection Extensions:

/// <summary>
/// Returns the collectionas a standard URL type QueryString
/// </summary>
/// <param name="self">The self.</param>
/// <returns></returns>
public static string ToQueryString(this NameValueCollection self)
{
string qsString = string.Empty;
if (self.Count > 0)
{
StringBuilder qsBuilder = new StringBuilder("?");

for (int i = 0; i < self.Keys.Count; i++)
{
if (self.Keys[i] != null && self.Keys[i].Length > 0)
{
qsBuilder.AppendFormat("{0}={1}&", HttpContext.Current.Server.UrlEncode(self.Keys[i]), HttpContext.Current.Server.UrlEncode(self[i]));
}
}

qsString = qsBuilder.ToString();
}

return qsString;
}


/// <summary>
/// Creates a copy the specified NameValueCollection.
/// </summary>
/// <param name="self">The NameValueCollection.</param>
/// <returns></returns>
public static NameValueCollection Copy(this NameValueCollection self)
{
return new NameValueCollection(self);
}


String Extensions

/// <summary>
/// Capitalizes the specified word.
/// </summary>
/// <param name="word">The word.</param>
/// <returns></returns>
public static string Capitalize(this string word)
{
if (word.IsNullOrEmpty())
{
return word;
}

// The aggregate is because IEnumerable.ToString doesn't return the characters as a string, it returns the type's name as a string.
return word[0].ToString().ToUpper() + word.Skip(1).Aggregate("", (s, c) => s + c);
}


/// <summary>
/// Splits the specified string into a list of white-space separated word strings.
/// </summary>
/// <param name="s">The s.</param>
/// <returns></returns>
public static IEnumerable Wordify(this string s)
{
return s.Split(new char[]{' ', '\n', '\t', '\r', '.', ',', ';', ':', '-'}, StringSplitOptions.RemoveEmptyEntries);
}

Wednesday, September 16, 2009

Custom styles in EPiServer WYSIWYG

If you've been using EPiServer for a while you'll know the frustration of the built in WYSIWYG editor for rich text entry. It's IE only and rather clunky.



There is a way to add your own custom HTML and CSS classes into the editor which get added to a drop down box.



By selecting an item from this drop down you can insert both HTML tags and classes into the text.

To do this you need to set the 'Path to CSS file for Editor' either in the Web.Config



<sitesettings uieditorcsspaths="/styles/episerver.css" />


In the CSS file the secret is a custom style attribute called EditMenuName which gives the name to put in the drop down list in the editor:

/*
Inserts <h1> </h1>
*/
h1
{
   EditMenuName:Heading1;
}

/*
Inserts <h2> </h2>
*/
h2
{
   EditMenuName:Heading2;
}

/*
Inserts <p class="intro"> </p>
*/
p.intro
{
   EditMenuName:IntroParagraph;
   padding-bottom: 1em;
   border-bottom: 1px solid #E8E8E8;
}

/*
Inserts <div class="box white"> </div>
*/
div.box white
{
   EditMenuName:Rounded Corner Box;
   border: solid 1px #E8E8E8;
   padding: 10px;
}

Thursday, June 18, 2009

Simple UrlRewriter for EpiServer

On an EpiServer project that I just finished there was a requirement that all URLs generated by the CMS should be lowercase. I couldn't really see the issue. I know that web servers are allowed to be case sensitive with URLs, but didn't really see the big deal.

However, looking at EpiServer, I thught that I might re-write a PageData extension method which I wrote previously which generates the external URL of a page:

public static string GetExternalUrl(this PageData page)
{
string result = String.Empty;

if (page != null)
{
UrlBuilder builder = new UrlBuilder(page.LinkURL);
EPiServer.Global.UrlRewriteProvider.ConvertToExternal
(builder, page, Encoding.UTF8);

result = builder.ToString();
}

return result;
}

This might have worked, but was still a bit of a kludge, so I turned to the undocumented waters of the EPiServer.Web.FriendlyUrlRewriteProvider

The FriendlyUrlRewriteProvider has a virtual method called:

ConvertToExternalInternal(EPiServer.UrlBuilder url, object internalObject, Encoding toEncoding)

Which is called by the EPiServer.Global.UrlRewriteProvider.ConvertToExternal(...) method I use in the Extension method above. Overriding that mehtod and converting the UrlBuilder's path property to lowercase seemed to do the trick.

Here's the final class:

public class LowerCaseUrlRewriteProvider : EPiServer.Web.FriendlyUrlRewriteProvider
{
public LowerCaseUrlRewriteProvider()
: base()
{

}

protected override bool ConvertToExternalInternal
(EPiServer.UrlBuilder url, object internalObject, Encoding toEncoding)
{
base.ConvertToExternalInternal(url, internalObject, toEncoding);

url.Path = url.Path.ToLower();

return true;
}
}



Update: Setting it up in the Web.Config

You now need to add this to the urlRewrite EpiServer config element in the Web.Config:

<urlRewrite defaultProvider="LowerCaseUrlRewriteProvider">
<providers>
<add name="LowerCaseUrlRewriteProvider" type="Shared.EpiServer.Web.LowerCaseUrlRewriteProvider,Shared.EpiServer" />
<add name="EPiServerFriendlyUrlRewriteProvider" type="EPiServer.Web.FriendlyUrlRewriteProvider,EPiServer" />
<add description="EPiServer identity URL rewriter" name="EPiServerIdentityUrlRewriteProvider"
type="EPiServer.Web.IdentityUrlRewriteProvider,EPiServer" />
<add description="EPiServer bypass URL rewriter" name="EPiServerNullUrlRewriteProvider"
type="EPiServer.Web.NullUrlRewriteProvider,EPiServer" />
</providers>
</urlRewrite>