BlogEngine.Net Widget – Article Info

aricle info I recently visited Karl Francisco Fernandes’s blog mesonprojekt (UPDATE 20-July-2012: This site is now dead!) with awesome design. There, while reading one of his blog entries, I saw this small widget on the right called “ABOUT THIS ARTICLE” and my heart just said – I want one.

Well that’s it. I tried(I swear I did) to search for it on internet for a while but soon ended up deciding to write my own. 

So since, I was going to write one for my own, I decided to write down my requirements (greyed out features are yet to be implemented.)

  1. To display well formatted information of currently viewed post.  
  2. To add support for date, author, categories and tags.
  3. To display well formatted information regarding comments.
  4. Link to Comments
  5. To add support for editable title.
  6. To add support for editable information format.
  7. To make the Widget visible on when a blog post is being displayed.
  8. To display the widget irrespective of the page/post the user is visiting, if the user is an Administrator.

Now that the requirements have been decided, I created blank templates for the widget and boom…..the first problem came in it’s way. How to access the current blog entry (Post in BlogEngine.Net) information from a widget? It’s pretty easy to do this from an extension, but Widgets that inherit from WidgetBase don’t have any methods to access the current Post. So, I went to the BlogEngine.Net codeplex site and searched for it on the forum. But there was no information there and so I ended up creating the thread of my own.

Soon Ben answered to the query and after couple of posts, I had all the information I needed to build my own post.

So based on Ben’s suggestions, I modified the WidgetBase.cs to include properties that allowed direct access to current Post/Page being served.

Here is what I added to WidgetBase.cs

#region Custom Properties
    /// <summary>
    /// Gets the current Page being served.
    /// </summary>
    /// <value>Current <c>Page</c> object if a Page is being served; otherwise <c>null</c>.</value>
    public BlogEngine.Core.Page CurrentPage
    {
        get { return GetCurrentPage(); }
    }

    /// <summary>
    /// Gets the current <c>Post</c> being served.
    /// </summary>
    /// <value>Current <c>Post</c> object if a Post is being served; otherwise <c>null</c>.</value>
    public BlogEngine.Core.Post CurrentPost
    {
        get { return GetCurrentPost(); }
    }

    private bool _DisplayWidget = true;

    /// <summary>
    /// Gets or Sets the visibility of Widget
    /// </summary>
    public bool DisplayWidget
    {
        get { return _DisplayWidget; }
        set { _DisplayWidget = value; }
    }
    #endregion

along with this functions (thanks to Ben)

#region additional Methods

    /// <summary>
    /// Function retreive the Current Post. Credit for this function 
    /// goes to Ben Amada (http://allben.net/)
    /// </summary>
    /// <returns></returns>
    private Post GetCurrentPost()
    {
        string currentPage = System.IO.Path.GetFileName(HttpContext.Current.Request.PhysicalPath);
        string id = Request.QueryString["id"];
        if (!string.IsNullOrEmpty(id) && id.Length == 36)
        {
            Guid itemId = new Guid(id);
            if (currentPage.Equals("post.aspx", StringComparison.OrdinalIgnoreCase))
            {
                return BlogEngine.Core.Post.GetPost(itemId);
            }
            else return null;
        }
        else return null;
    }
    
    /// <summary>
    /// Function retreive the Current Page. Credit for this function 
    /// goes to Ben Amada (http://allben.net/)
    /// </summary>
    /// <returns></returns>
    private BlogEngine.Core.Page GetCurrentPage()
    {
        string currentPage = System.IO.Path.GetFileName(HttpContext.Current.Request.PhysicalPath);
        string id = Request.QueryString["id"];
        if (!string.IsNullOrEmpty(id) && id.Length == 36)
        {
            Guid itemId = new Guid(id);
            if (currentPage.Equals("page.aspx", StringComparison.OrdinalIgnoreCase))
            {
                return BlogEngine.Core.Page.GetPage(itemId);
            }
            else return null;
        }
        else return null;
    }

    #endregion

So, as you can see, apart from CurrentPost & CurrentPage, there is an extra property called DisplayWidget. Well, this part certainly wasn’t my idea but the happened to ask about this feature in my thread and it was exactly what I needed ;). So, this property lets BlogEngine.Net decide which Widgets are to be diplayed. But how will BlogEngine.Net decide that. Well, tha’s where we need to modify WidgetZone.cs file. Here you need to replace

this.Controls.Add(control);

with

//Added: Implementing DisplayWidget property
 if (!control.DisplayWidget)
{
	if (Page.User.Identity.IsAuthenticated && Roles.IsUserInRole(BlogEngine.Core.BlogSettings.Instance.AdministratorRole))
	{
		this.Controls.Add(control);
	}
}
else this.Controls.Add(control);

That’s it. Now, we have three properties at our disposal when we inherit from WidgetBase.

  1. CurrentPost – Gets a Post object if a blog entry is being served; otherwise null;
  2. CurrentPage – Gets a Page object if a page is being served; otherwise null;
  3. DisplayWidget – Gets or Sets the visibility of the Widget. If set to false, the widget won’t be displayed. The property has not effect when the user has logged in as Administrator.

So, here is the code for widget.ascx

<%@ Control Language="C#" AutoEventWireup="true" CodeFile="widget.ascx.cs" Inherits="widgets_articleinfo_widget" %>
<asp:Label ID="articleInfo" runat="server"></asp:Label>
<div id="commentLinks" runat="server">
<asp:HyperLink runat="server" ID="hlViewComment">View Comments</asp:HyperLink>
</div>

 

and widget.ascx.cs

#region Using

using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.HtmlControls;
using System.Web.Caching;
using System.Xml;
using System.IO;
using System.Text;
using System.Text.RegularExpressions;
using BlogEngine.Core;
using System.Globalization;

#endregion

public partial class widgets_articleinfo_widget : WidgetBase
{
    /// <summary>
    /// (1) Title, (2) Author, (3) DateCreated, (4) Categories
    /// </summary>
    string POSTINFO = "You are reading <b>\"{0}\"</b>, an entry posted by {1} on {2} and categorized under {3}.";
    //string PAGEINFO = "You are currently on \"{0}\" page.";

    string TAGLIST = "The following tags are associated with this article: {0}";

    string NOCOMMENTS = "There are no comments for this article.";
    string SINGLECOMMENTS = "There is only 1 comment for this article.";
    string MULTIPLECOMMENTS = "There are {0} comments for this article.";
    
	public override string Name
	{
		get { return "Article Info"; }
	}

	public override bool IsEditable
	{
		get { return true; }
	}
    
	public override void LoadWidget()
	{
        if (this.CurrentPost == null)
        {
            this.DisplayWidget = false;
            return;
        }

        Post curPost = this.CurrentPost;
        StringBuilder sb = new StringBuilder();

        sb.AppendLine("<div>");
        sb.AppendFormat(this.POSTINFO, curPost.Title.ToString(), curPost.Author.ToString(), curPost.DateCreated.ToString("MMMM dd, yyyy"), this.CategoryLinks(curPost,", "));

        if (curPost.Tags.Count != 0)
        {
            sb.Append("<br /><br />");
            sb.AppendFormat(this.TAGLIST,this.TagLinks(curPost,", "));
        }

        sb.Append("<br /><br />");

        int CommentCount = curPost.ApprovedComments.Count;

        if(CommentCount  == 0)
        {
            sb.Append(this.NOCOMMENTS);
        }else if(CommentCount == 1){
            sb.Append(this.SINGLECOMMENTS);
        }else sb.AppendFormat(this.MULTIPLECOMMENTS,CommentCount);

        sb.AppendLine("</div>");

        this.articleInfo.Text = sb.ToString();

        this.hlViewComment.NavigateUrl = curPost.RelativeLink + "#comment";

    }

    #region Methods from PostViewBase
    protected virtual string CategoryLinks(Post curPost, string separator)
    {
        string[] keywords = new string[curPost.Categories.Count];
        string link = "<a href=\"{0}{1}.aspx\">{2}</a>";
        string path = VirtualPathUtility.ToAbsolute("~/category/");
        for (int i = 0; i < curPost.Categories.Count; i++)
        {
            if (Category.Categories.Contains((Category)curPost.Categories[i]))
            {
                string category = Category.GetCategory(curPost.Categories[i].Id).Title;
                keywords[i] = string.Format(CultureInfo.InvariantCulture, link, path, Utils.RemoveIllegalCharacters(category), category);
            }
        }


        return string.Join(separator, keywords);
    }

    /// <summary>
    /// Displays the Post's tags seperated by the specified string.
    /// </summary>
    protected virtual string TagLinks(Post post, string separator)
    {
        if (post.Tags.Count == 0)
            return null;

        string[] tags = new string[post.Tags.Count];
        string link = "<a href=\"{0}/{1}\" rel=\"tag\">{2}</a>";
        string path = Utils.RelativeWebRoot + "?tag=";
        for (int i = 0; i < post.Tags.Count; i++)
        {
            string tag = post.Tags[i];
            tags[i] = string.Format(CultureInfo.InvariantCulture, link, path, HttpUtility.UrlEncode(tag), HttpUtility.HtmlEncode(tag));
        }

        return string.Join(separator, tags);
    }
    #endregion
}

As you can see, I’ve left IsEditable to true and added an empty edit.ascx to use the inbuilt Widget Title Editing feature. You can watch the working demo on the side-bar. Do tell me if you like it.

Also, I would like to Ben for his codes and suggestions. They were the valuable piece of information for this Widget.

 

 

How to install the Widget?

  • Download the widget from the download link given below.
  • Extract the files to your local folder
  • As you can see, the files are already in structure they need to be copied.
  • Copy WidgetBase.cs and WidgetZone.cs from App_Code\Controls to yours servers ~/App_Code/Controls folder
  • Also copy the Article Info folder from widgets to your servers’ ~/widgets folder.
  • And you are done.
  • You can add your widget by selecting it from the drop-down list of your WidgetZone.

Note: This widget will work on themes that support Widgets.

 

 

So. Do you want one?

Download Article Info