Extend SharePoint Activity Feed Web Part

Today I want to show you how you could customize out-of-the-box Activity Feed Web Part from SharePoint.

I want to share with you my solution of how you could extend it in a way that new activities from last two days are shown with some special color and status indicator which inform you about that as you can see in a picture above.

So, lets start.

Firstly, we have to create new Visual Web Part named MojeAktivnostiVWP inside of our SharePoint Project Visual Studio Solution.

After that we have to replace MojeAktivnostiVWP.webpart file with MojeAktivnostiVWP.dwp. Inside of it you have to put this web part settings:

<?xml version="1.0" encoding="utf-8"?>
<WebPart xmlns="http://schemas.microsoft.com/WebPart/v2" xmlns:iwp="http://schemas.microsoft.com/WebPart/v2/Image">
  <Assembly>$SharePoint.Project.AssemblyFullName$</Assembly>
  <TypeName>TestProject.Contents.WebParts.MojeAktivnostiVWP.MojeAktivnostiVWP</TypeName>
  <Title>Moje aktivnosti</Title>
  <Description>Moje aktivnosti</Description>
  <PartOrder>3</PartOrder>
  <FrameType>None</FrameType>
  <AllowMinimize>true</AllowMinimize>
  <AllowRemove>true</AllowRemove>
  <IsVisible>true</IsVisible>
  <iwp:ImageLink>/_layouts/15/images/TestProject/xnet-feature-logo.png</iwp:ImageLink>
</WebPart>

Please check if you have dwp file defined inside of Elements.xml file of your Web Part like in this example below:

<?xml version="1.0" encoding="utf-8"?>
<Elements xmlns="http://schemas.microsoft.com/sharepoint/" >
  <Module Name="MojeAktivnostiVWP" List="113" Url="_catalogs/wp">
    <File Path="MojeAktivnostiVWP\MojeAktivnostiVWP.dwp" Url="Xnet.SP.KompAS2_MojeAktivnostiVWP.dwp" Type="GhostableInLibrary" >
      <Property Name="Group" Value="Custom" />
    </File>
  </Module>
</Elements>

Then we have to define front-end of our WebPart which is very simple:

<%@ Assembly Name="$SharePoint.Project.AssemblyFullName$" %>
<%@ Assembly Name="Microsoft.Web.CommandUI, Version=16.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %> 
<%@ Register Tagprefix="SharePoint" Namespace="Microsoft.SharePoint.WebControls" Assembly="Microsoft.SharePoint, Version=16.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %> 
<%@ Register Tagprefix="Utilities" Namespace="Microsoft.SharePoint.Utilities" Assembly="Microsoft.SharePoint, Version=16.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
<%@ Register Tagprefix="asp" Namespace="System.Web.UI" Assembly="System.Web.Extensions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" %>
<%@ Import Namespace="Microsoft.SharePoint" %> 
<%@ Register Tagprefix="WebPartPages" Namespace="Microsoft.SharePoint.WebPartPages" Assembly="Microsoft.SharePoint, Version=16.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
<%@ Control Language="C#" AutoEventWireup="true" CodeBehind="MojeAktivnostiVWP.ascx.cs" Inherits="TestProject.Contents.WebParts.MojeAktivnostiVWP.MojeAktivnostiVWP" %>

<div id="mojeAktivnostiVWP">
    <asp:PlaceHolder ID="phConsole" runat="server"></asp:PlaceHolder>
</div>

And last and the biggest thing is back-end which we have it here:

using System;
using System.ComponentModel;
using System.Web.UI.WebControls.WebParts;
using Microsoft.SharePoint;
using System.Web.UI;
using TestProject.Utilities;
using System.Web;
using Microsoft.SharePoint.Portal.WebControls;
using Microsoft.Office.Server.Social;
using Microsoft.SharePoint.Utilities;
using System.Globalization;
using Microsoft.SharePoint.WebControls;
using Microsoft.SharePoint.Administration;
using Microsoft.SharePoint.Flighting.Runtime;
using System.Linq;

namespace TestProject.Contents.WebParts.MojeAktivnostiVWP
{
    [ToolboxItemAttribute(false)]
    public partial class MojeAktivnostiVWP : FeedWebPartBase
    {
        private int countNewItems = 0;

        public MojeAktivnostiVWP()
        {
        }

        protected override void OnInit(EventArgs e)
        {
            base.OnInit(e);
            base.ShowPostBox = false;
        }

        protected override void OnPreRender(object sender, EventArgs e)
        {
            base.DisplayName = ((base.OwnerProfile != null) ? base.OwnerProfile.DisplayName : "");
            base.RegisterScripts();

            try
            {
                ErrorString = "";
                StatusCode = -1;
                InitialFeed = null;
                CurrentUser = null;

                using (SPSite site = new SPSite(SPContext.Current.Site.ID))
                {
                    SPServiceContext context = SPServiceContext.GetContext(site);
                    using (new SPServiceContextScope(context))
                    {
                        SPSocialFeedManager sfm = new SPSocialFeedManager();
                        CurrentUser = sfm.Owner;

                        SPSocialFeedOptions options = new SPSocialFeedOptions()
                        {
                            SortOrder = SPSocialFeedSortOrder.ByCreatedTime,
                            MaxThreadCount = 10
                        };

                        SPSocialFeed feed = InitialFeed = sfm.GetFeed(SPSocialFeedType.Timeline, options);

                        countNewItems = feed.Threads.Where(x => x.RootPost.CreatedTime >= new DateTime(DateTime.Now.Year, DateTime.Now.Month, DateTime.Now.Day, 0, 0, 0).AddDays(-2)).Count();
                        
                        if (countNewItems > 0)
                        {
                            var statusBar = new SPPageStatusSetter();
                            statusBar.AddStatus("Aktivnosti", "V zadnjih dveh dneh imate nove aktivnosti (" + countNewItems + "). Ogledate si jih lahko spodaj.", SPPageStatusColor.Yellow);
                            Controls.Add(statusBar);
                        }
                    }
                }
            }
            catch (Exception _ex)
            {
                Logger.ToLog(_ex, "Error MojeAktivnostiVWP");
            }

            RegisterStartupScriptForPersistentFeed(false, "");

            this.OnPreRender(e);
        }

        private string GetChangePhotoUrl()
        {
            return SPContext.Current.Site.Url + "/" + SPUtility.ContextLayoutsFolder + "/changephoto.aspx?Source=" + SPHttpUtility.UrlKeyValueEncode(SPAlternateUrl.ContextUri.ToString());
        }

        private string GetEditProfileUrl()
        {
            var usp = SPContext.Current.Site.WebApplication.UserSettingsProvider;

            string baseUrl = SPContext.Current.Site.Url + "/" + SPUtility.ContextLayoutsFolder + "/EditProfile.aspx";

            baseUrl = Helper.SafeAppendQueryStringParameter(baseUrl, "UserSettingsProvider", usp.ProviderIdentifier.ToString());

            baseUrl = Helper.SafeAppendQueryStringParameter(baseUrl, "ReturnUrl", SPHttpUtility.UrlKeyValueEncode(SPAlternateUrl.ContextUri.ToString()));

            return baseUrl;
        }

        private void RegisterStartupScriptForPersistentFeed(bool isSiteFeed, string siteId)
        {
            string text = ((!isSiteFeed || !VariantConfiguration.IsGlobalExpFeatureToggleEnabled(Microsoft.SharePoint.Flighting.ExpFeatureId.SiteFeedRTsReduction)) ? ((OwnerProfile != null) ? SPHttpUtility.EcmaScriptStringLiteralEncode(OwnerProfile.AccountName) : "") : "");

            string text2 = "SP.SOD.executeFunc('SP.UI.Microfeed.js', 'SP.UI.MicroFeed.SPMicroFeed.initializePublishedFeed', function() { SP.UI.MicroFeed.SPMicroFeed.initializePublishedFeed(\r\n                                '" + text + "',\r\n                                '" + SPHttpUtility.EcmaScriptStringLiteralEncode(DisplayName) + "',\r\n                                '" + ((!isSiteFeed) ? SPHttpUtility.EcmaScriptStringLiteralEncode(GetEditProfileUrl()) : "") + "',\r\n                                '" + ((!isSiteFeed) ? SPHttpUtility.EcmaScriptStringLiteralEncode(GetChangePhotoUrl()) : "") + "',\r\n                                " + ShowPostBox.ToString().ToLower(CultureInfo.InvariantCulture) + ",\r\n                                " + isSiteFeed.ToString().ToLower(CultureInfo.InvariantCulture) + ",\r\n                                '" + SPHttpUtility.EcmaScriptStringLiteralEncode(siteId) + "',\r\n                                " + HasWritePermission.ToString().ToLower(CultureInfo.InvariantCulture) + ");});";
            SPPageContentManager.RegisterStartupScript(((Control)this).Page, base.GetType(), "__MicroFeedWebpartScript__", text2);
        }

        protected override void RenderWebPart(HtmlTextWriter writer)
        {
            base.WriteInitialDataToPage(writer, "");

            writer.Write("<style>div#mojeAktivnostiVWP div.ms-microfeed-thread{ margin: 5px 0px; padding: 5px 10px; }</style>");

            if (countNewItems > 0)
                writer.Write("<style>div#mojeAktivnostiVWP div.ms-microfeed-thread:nth-child(-n+" + countNewItems + "){ background-color: #fff19d; border: 1px #d7d889 solid; }</style>");

            base.RenderWebPart(writer);
        }

        protected void Page_Load(object sender, EventArgs e)
        {
        }
    }
}

As you can see we extend FeedWebPartBase abstract class and we have to override next methods:

  • OnInit()
  • OnPreRender()
  • RenderWebPart()

On OnPreRender() method we set DisplayName and InitialFeed from base class. Besides we count new items from last two days into countNewItems variable.

We have to execute SP.UI.MicroFeed.SPMicroFeed.initializePublishedFeed function from SP.UI.Microfeed.js script file. This is done in RegisterStartupScriptForPersistentFeed() method.

Inside of RenderWebPart overrided method we have to call WriteInitialDataToPage method of base class and we add some additional css styling blocks.

That’s all folks. Have fun and happy coding! 🙂

Cheers!
Gašper Rupnik

{End.}

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

Powered by WordPress.com.

Up ↑

%d bloggers like this: