Thursday, December 9, 2010

TagCloud Webpart in SharePoint 2007

While everyone else right now seems to be blogging about SharePoint 2010, I decided to blog a little bit about the previous product, SharePoint 2007.

Recently, I had to develop a webpart that shows Tags from either a Site collection level or subsite level.

I will give you the code but firstly, here is how it works:

Assumining that you already have a library/list that has a choice field called Category(it can have any name), the webpart will search the site collection/subsite(depending on the scope you choose) for all columns that are named 'Category', and when found, will pull out the selected choices for display. Remember that this is a choice column, meaning that the choices will be repeatitive, and therefore, the more repeative the choices are, the bigger the font size of the Tag name will appear on the webpart.

Secondly, the tags will get random colors on page load, while at the same time will be hyperlinked, and when you click on a tag, it will be passed to the Search and generate search results for you on the search page to library/list items you have permissions on.

Thirdly, on the webpart properties, you get the privilege of changing the choice column name to point to, the scope(site collection or subsite), as well as change the search string to use, and also enable caching etc.

Fouthly, I have a feeling that this is going to be the longest blog post have ever made, nevertheless, the following is the name space code:

**remember to generate your own GUID.

using System;
using System.Data;
using System.Text;
using System.Drawing;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Xml.Serialization;
using System.Collections.Generic;
using System.ComponentModel;

using Microsoft.SharePoint;
using Microsoft.SharePoint.Publishing;
using Microsoft.SharePoint.WebControls;
using Microsoft.SharePoint.WebPartPages;

namespace TagCloud.TagCloud
{
[Guid("9eb18673-6617-4c63-b716-8cf8f935318e")]
public class TagCloudClass : System.Web.UI.WebControls.WebParts.WebPart
{
// Fields
private string documentLibraryType = "1";
private bool isActivatedCache = true;
private string listType = "0";
private bool openItemsInNewWindows;
private readonly Random rnd = new Random(DateTime.Now.Millisecond);
private Enumerations.SearchScopes scope = Enumerations.SearchScopes.SiteCollection;
private char separator = ',';
private string tagField = "Category";
private readonly Dictionary Tags = new Dictionary();
private string targetUrl = "/_layouts/OSSSearchResults.aspx?k=";

// Methods
public TagCloudClass()
{
this.rnd = new Random(DateTime.Now.Millisecond);
this.Tags = new Dictionary();
this.documentLibraryType = "1";
this.listType = "0";
this.scope = Enumerations.SearchScopes.SiteCollection;
this.separator = ',';
this.tagField = "Category";
this.targetUrl = "/_layouts/OSSSearchResults.aspx?k=";
this.isActivatedCache = true;
}


private void AddLinks(string key)
{
Tag tag = this.Tags[key];
this.AddSeparator();
Table child = new Table();
child.Width = new Unit(100.0, UnitType.Percentage);
foreach (TagLink link in tag.Links)
{
TableRow row = new TableRow();
child.Rows.Add(row);
TableCell cell = new TableCell();
row.Cells.Add(cell);
HyperLink link2 = new HyperLink();
link2.Text = link.Title;
link2.NavigateUrl = link.ItemUrl;
cell.Controls.Add(link2);
}
this.Controls.Add(child);
}

private void AddSeparator()
{
Table child = new Table();
child.Width = new Unit(100.0, UnitType.Percentage);
TableRow row = new TableRow();
child.Rows.Add(row);
TableCell cell = new TableCell();
cell.HorizontalAlign = HorizontalAlign.Center;
row.Cells.Add(cell);
Label label = new Label();
label.Text = "----------------";
cell.Controls.Add(label);
this.Controls.Add(child);
}

private void AddTag(DataRow row, string localTag)
{
Tag newTag = new Tag();
newTag.Title = localTag;
SaveTag(newTag, row);
this.Tags.Add(localTag, newTag);
}

private void AddTags(string listType, Enumerations.SearchScopes searchScope)
{
DataTable results = this.GetResults(listType, searchScope);
this.GetTags(results);
}

private void BuildWebPart()
{
try
{
this.AddTags(this.ListType, this.Scope);
this.AddTags(this.DocumentLibraryType, this.Scope);
Table child = new Table();
child.Width = new Unit(100.0, UnitType.Percentage);
TableRow row = new TableRow();
child.Rows.Add(row);
TableCell cell = new TableCell();
cell.HorizontalAlign = HorizontalAlign.Center;
row.Cells.Add(cell);
this.Controls.Add(child);
foreach (KeyValuePair pair in this.Tags)
{
LinkButton button = new LinkButton();
button.Text = pair.Value.Title;
int count = pair.Value.Links.Count;
button.ToolTip = string.Format("{0} occurrance", count);
button.Font.Size = new FontUnit(GetFontSize(count), UnitType.Point);
button.ForeColor = this.GetRandomColor();
button.CommandArgument = pair.Key;
button.Click += new EventHandler(this.Tag_Click);
cell.Controls.Add(button);
Literal literal = new Literal();
literal.Text = " ";
cell.Controls.Add(literal);
}
}
catch (Exception exception)
{
this.SetErrorMessage(exception);
}
}

protected override void CreateChildControls()
{
base.CreateChildControls();
this.BuildWebPart();
}

private static string GetErrorMessage(Exception ex)
{
StringBuilder builder = new StringBuilder();
try
{
StackTrace trace = new StackTrace(ex, true);
builder.AppendLine(string.Format(" Stack trace for current level: {0}", trace));
StackFrame[] frames = trace.GetFrames();
if (frames != null)
{
foreach (StackFrame frame in frames)
{
builder.AppendLine(string.Format(" File: {0}", frame.GetFileName()));
builder.AppendLine(string.Format(" Method: {0}", frame.GetMethod().Name));
builder.AppendLine(string.Format(" Line Number: {0}", frame.GetFileLineNumber()));
builder.AppendLine(string.Format(" Column Number: {0}", frame.GetFileColumnNumber()));
}
}
}
catch
{
}
return builder.ToString();
}

private static double GetFontSize(int count)
{
double num = 8.0;
switch (count)
{
case 2:
num = 10.0;
break;

case 3:
num = 12.0;
break;

case 4:
num = 14.0;
break;

case 5:
num = 16.0;
break;

case 6:
num = 18.0;
break;

case 7:
num = 20.0;
break;

case 8:
num = 22.0;
break;

case 9:
num = 24.0;
break;
}
if (count > 10)
{
num = 26.0;
}
return num;
}

private static string GetItemUrl(string s)
{
string str = string.Empty;
try
{
string str2 = s.Split(new char[] { '#' })[1];
string str3 = str2.Remove(str2.LastIndexOf('/'));
string str4 = s.Substring(s.LastIndexOf('/') + 1);
string str5 = str4.Remove(str4.LastIndexOf('_'));
str = SPContext.Current.Web.Site.Url + "/" + str3 + "/DispForm.aspx?ID=" + str5;
}
catch (Exception)
{
}
return str;
}

private Color GetRandomColor()
{
Color black = Color.Black;
try
{
int red = this.rnd.Next(0, 0xff);
int green = this.rnd.Next(0, 0xff);
int blue = this.rnd.Next(0, 0xff);
black = Color.FromArgb(red, green, blue);
}
catch
{
}
return black;
}

private DataTable GetResults(string listType, Enumerations.SearchScopes searchScope)
{
string str = "";
string str2 = string.Format("", this.TagField);
string str3 = "";
if (!this.isActivatedCache)
{
SPSiteDataQuery query = new SPSiteDataQuery();
query.Lists = str;
query.ViewFields = str2;
query.Webs = str3;
return SPContext.Current.Web.GetSiteData(query);
}
CrossListQueryInfo queryCacheInfo = new CrossListQueryInfo();
queryCacheInfo.WebUrl = SPContext.Current.Site.ServerRelativeUrl;
queryCacheInfo.Lists = str;
queryCacheInfo.Webs = str3;
queryCacheInfo.Query = string.Format("", this.TagField);
queryCacheInfo.ViewFields = str2;
CrossListQueryCache cache = new CrossListQueryCache(queryCacheInfo);
return cache.GetSiteData(SPContext.Current.Site);
}

private void GetTag(DataRow row, string tag)
{
if (this.Tags.ContainsKey(tag))
{
this.UpdateTag(row, tag);
}
else
{
this.AddTag(row, tag);
}
}

private void GetTags(DataTable results)
{
foreach (DataRow row in results.Rows)
{
string[] strArray = row[3].ToString().Split(new char[] { this.Separator });
foreach (string str in strArray)
{
this.GetTag(row, str.Trim());
}
}
}

private static void SaveTag(Tag newTag, DataRow row)
{
TagLink item = new TagLink();
item.ListID = new Guid(row[0].ToString());
item.WebID = new Guid(row[1].ToString());
item.ItemUrl = GetItemUrl(row[4].ToString());
item.Title = row[5].ToString();
newTag.Links.Add(item);
}

private void SetErrorMessage(Exception ex)
{
this.Controls.Clear();
Label child = new Label();
child.Text = GetErrorMessage(ex);
child.CssClass = "ms-formvalidation";
this.Controls.Add(child);
}

private void Tag_Click(object sender, EventArgs e)
{
LinkButton button = sender as LinkButton;
if (button != null)
{
if (string.IsNullOrEmpty(this.TargetUrl))
{
this.AddLinks(button.CommandArgument);
}
else
{
this.Page.Response.Redirect(this.TargetUrl + button.CommandArgument);
}
}
}

private void UpdateTag(DataRow row, string localTag)
{
Tag newTag = this.Tags[localTag];
SaveTag(newTag, row);
}

// Properties
public string DocumentLibraryType
{
get
{
return this.documentLibraryType;
}
set
{
this.documentLibraryType = value;
}
}

[Personalizable(PersonalizationScope.Shared), FriendlyName("Enable Cache"), Description("Flag for activating the cache"), Category("Parameters"), PersistenceMode(PersistenceMode.InnerProperty), WebBrowsable(true)]
public bool IsActivatedCache
{
get
{
return this.isActivatedCache;
}
set
{
this.isActivatedCache = value;
}
}

public string ListType
{
get
{
return this.listType;
}
set
{
this.listType = value;
}
}

[Personalizable(PersonalizationScope.Shared), Description("If checked, allows to open all links in a new window Tag"), Category("Parameters"), PersistenceMode(PersistenceMode.InnerProperty), WebBrowsable(true), FriendlyName("Open links in a new window")]
public bool OpenItemsInNewWindows
{
get
{
return this.openItemsInNewWindows;
}
set
{
this.openItemsInNewWindows = value;
}
}

[Category("Parameters"), Personalizable(PersonalizationScope.Shared), FriendlyName("Search Scope"), Description("Set the search scope for Tag: only the current site or the entire site collection"), WebBrowsable(true), PersistenceMode(PersistenceMode.InnerProperty)]
public Enumerations.SearchScopes Scope
{
get
{
return this.scope;
}
set
{
this.scope = value;
}
}

[WebBrowsable(true), Description("Set the value of the separator character for Tag"), Category("Parameters"), PersistenceMode(PersistenceMode.InnerProperty), Personalizable(PersonalizationScope.Shared), FriendlyName("Separator character for Tag")]
public char Separator
{
get
{
return this.separator;
}
set
{
this.separator = value;
}
}

[PersistenceMode(PersistenceMode.InnerProperty), Category("Parameters"), Personalizable(PersonalizationScope.Shared), FriendlyName("Tag Name column to search"), WebBrowsable(true), Description("Sets the name tag on the columns to search")]
public string TagField
{
get
{
return this.tagField;
}
set
{
this.tagField = value;
}
}

[WebBrowsable(true), Personalizable(PersonalizationScope.Shared), Description("Set the URL of the page to search for Tag"), FriendlyName("Url of the page to search for Tag"), Category("Parameters"), PersistenceMode(PersistenceMode.InnerProperty)]
public string TargetUrl
{
get
{
return this.targetUrl;
}
set
{
this.targetUrl = value;
}
}

}
internal class TagLink
{
// Fields
private string itemUrl;
private Guid listID;
private string title;
private Guid webID;

// Properties
public string ItemUrl
{
get
{
return this.itemUrl;
}
set
{
this.itemUrl = value;
}
}

public Guid ListID
{
get
{
return this.listID;
}
set
{
this.listID = value;
}
}

public string Title
{
get
{
return this.title;
}
set
{
this.title = value;
}
}

public Guid WebID
{
get
{
return this.webID;
}
set
{
this.webID = value;
}
}
}


internal class Tag
{
// Fields
private List links = new List();
private string title;

// Properties
public List Links
{
get
{
return this.links;
}
set
{
this.links = value;
}
}

public string Title
{
get
{
return this.title;
}
set
{
this.title = value;
}
}
}


public class Enumerations
{
// Nested Types
public enum SearchScopes
{
SiteCollection,
Recursive,
Web
}
}
}



Happy days!!!
References: http://www.codeplex.com/

No comments: