Home | Blog | Screencasts | Projects
# Thursday, September 25, 2008

I’ve previously posted a demo that made use of a tag suggestion web part, as you type the web part will make an ajax call which will return the tags that match the current input. The user can click on the suggestion tag and it will populate the textbox, multiple tags can be entered into the textbox.

image

 

The most interesting part of this web part is the server side call, which I’ve implemented as a HttpHandler in the Tags.ashx file:

 

public class Handler : IHttpHandler {

    public void ProcessRequest(HttpContext context)
    {
        context.Response.ContentType = "text";

 

I’ve made use of the System.Web.Extensions JavaScriptSerializer to render the string array of tags to JSON:

   1: List<string> tagList = new List<string>();
   2:  
   3: //add all the tags to a collection, JSON serialize the list
   4:  
   5: System.Web.Script.Serialization.JavaScriptSerializer serializer = new System.Web.Script.Serialization.JavaScriptSerializer();
   6:  
   7: context.Response.Write(serializer.Serialize(tagList.ToArray()));
   8:  

I’ve put this handler in the /_vti_bin/ directory of SharePoint which maps to the ISAPI folder under the 12 hive.

 

I’ve used the same code to generate the tags as I did with the tag cloud web part, so once again the generation of these tags won’t scale to large lists, this is just an example of how to implement a JQuery based Tag Suggestion web part.

 

The source code for this web part can be found here.

Thursday, September 25, 2008 7:39:59 PM (E. Australia Standard Time, UTC+10:00)  #    Comments [0] - Trackback
code | Sharepoint | Work
# Wednesday, September 24, 2008

Just a quick tip, if your crawling external sources with the MOSS (or Enterprise Search), you might find that your crawl doesn’t finish or hangs, it might be worthwhile checking to see if the site you are crawling has a calendar with links:

 

image

 

You will need to determine the URL and then add a crawl rule to exclude that path, the crawler will see an infinite number of pages (it thinks each date and next link is a separate page).

Wednesday, September 24, 2008 1:17:00 PM (E. Australia Standard Time, UTC+10:00)  #    Comments [0] - Trackback
MOSS | Search | Sharepoint
# Tuesday, September 23, 2008

I recently had a project where I needed to bind some business objects to a SPGridView in a web part, which on its own is trivial, but I also needed to create the columns for the SPGridView on the fly, since a number of business objects could be rendered in this control.

The main problem was the naming of these columns, if I just bound them directly to the Grid, I would get the ugly naming of my properties (I say it’s ugly, it’s actually pretty awesome if your a developer, but those pesky end users like pretty names).

The sample grid looks like this by default:

 

grid-without

 

So what I came up with isn’t exactly new or innovative, I created a custom attribute called Alias:

 

    public class AliasAttribute : System.Attribute
    {
        protected string[] aliasName;

        public AliasAttribute(params string[] alias)
        {
            this.aliasName = alias;
        }

        public string[] Alias
        {
            get { return aliasName; }
            set { aliasName = value; }
        }
    }

 

This attribute gets applied to each property on your business object with a pretty name:

 

        [Alias("Internet URL")]
        public string InternetAddress
        {
            get { return internetAddress; }
            set { internetAddress = value; }
        }

 

Now the code that performs the binding looks for properties with a custom attribute and pulls out the alias as the HeaderText:

BoundField newBoundField = new BoundField();
newBoundField.HeaderText = Helpers.GetPropertyAlias(field.Trim());
newBoundField.DataField = field.Trim();
grid.Columns.Add(newBoundField);
public static string GetPropertyAlias(string propertyName)
{
    //Change the next line for your business object ..
    PropertyInfo[] propInfos = typeof(BusinessObject).GetProperties();

    foreach (PropertyInfo propInfo in propInfos)
    {
        if (propInfo.Name.ToUpper().Equals(propertyName.ToUpper()))
        {
            object[] attribs = propInfo.GetCustomAttributes(typeof(AliasAttribute), true);
            foreach (object attrib in attribs)
            {
                if (attrib is AliasAttribute)
                {
                    AliasAttribute alias = (AliasAttribute)attrib;
                    //return the alias
                    return alias.Alias[0];
                }
            }
        }
    }

    //if we don't find the custom attribute, just return the same value we passed in
    return propertyName;
}

 

The end result is a nice pretty grid:

 

Grid-With

 

A sample project can be found here.

Tuesday, September 23, 2008 10:20:00 AM (E. Australia Standard Time, UTC+10:00)  #    Comments [0] - Trackback
code | MOSS | Sharepoint
# Monday, September 22, 2008

If you work in an organisation that has an organisation hierarchy it might be worth setting this up within MOSS, so that when you view a user’s profile you will get the following view:

OrgHeir

 

This is driven off the Manager profile field, it can be setup so that it is driven off either active directory or a custom source such as a SQL database in which case the BDC will need to be used. The Colleague suggestions and notifications make use of the organisation hierarchy as well, so it is worthwhile to set it up.

One thing but, regardless of your localisation settings, the heading ‘Organization Hierarchy’ will be spelt with a ‘z’, so for us Aussie’s we just have to cop the American spelling.

Monday, September 22, 2008 9:33:00 AM (E. Australia Standard Time, UTC+10:00)  #    Comments [0] - Trackback
Sharepoint | Work
# Thursday, September 18, 2008

The SharePoint Capacity Planning tool can be found here. The executive overview can be found here.

 

The process of creating a model is very simple:

image

 

The UI is wizard based and it asks a number of questions, it's all high level stuff that shouldn't present any issues:

 

image

 

The notes from the overview point out that the tool gives a first approximation, we’ve found that it does a good job recommending hardware, but that the topology of the recommended farms could use some extra thought.

 

For example, if you created a single intranet site with 25000 users with a heavy collaboration usage profile, the tool will recommend 6 servers, 2 of which are SQL Servers. The tool recommends 3 web front ends and an index server.

Now I’m sure this would work fine, but some questions you could ask are:

Could adding a dedicated web front end that isn’t in the load balanced cluster but that is used to service the indexer add to the performance of the site, since the crawler isn’t competing with end users for resources?

The tool doesn't go into the logical architecture of the SharePoint farm, it's purely hardware related.

 

 

image

 

Overall I think the tool is very worthwhile, your planning should definitely include running this tool, but don’t let this tool do all the work, do a little bit of thinking for yourself.

Thursday, September 18, 2008 9:06:12 AM (E. Australia Standard Time, UTC+10:00)  #    Comments [0] - Trackback
Sharepoint | Planning
# Tuesday, September 16, 2008

If you run your SQL Server on a non standard port you may have experienced issues when installing SharePoint on this server. The standard psconfig utility has a field for the server name, if you give it a comma and then the port your SQL box is running on it will fail. The psconfig wizard doesn't understand the port number format. This isn't just related to SharePoint, I had to use this same trick when I was doing a Great Plains install.

The trick is to create an Alias, first run 'cliconfg', you should be presented with the following UI:

 

image

 

Select the Alias tab, then Add - you should then see the above dialog. Now you just need to enter the server alias, I normally just make this the server name, but your circumstances may be different, then unselect the 'Dynamically determine port' checkbox so you can enter the port number that your SQL Server runs on.

Once the Alias is setup you can refer to the SQL Server by the server alias that you have setup here.

Tuesday, September 16, 2008 9:02:54 AM (E. Australia Standard Time, UTC+10:00)  #    Comments [0] - Trackback
configuration | Sharepoint | SQL Server
# Monday, September 15, 2008

I found this fantastic post today that I just had to comment on:

 

In a SharePoint entry form the user can select multiple values from a list. This should include an “All” option so in a long list the user can select or de-select all values with one click.

 

The idea is to use JQuery to perform a select 'All' on all the checkboxes in a list.

DannyE posted this JavaScript:

 

$(”.ms-RadioText[title=’All’] :checkbox”).click(function(){
   var otherids = (this.id).substring(0, (this.id).length-2 );
   $(”input[id^=’”+otherids+”‘]”).attr( “checked” , (this.checked)?”checked”:”" );
});

 

It looks for all the items with the ms-RadioText class that also have a Title attribute that equals 'All', it adds a click handler that will then toggle the checked status of the checkbox, its extremely cool, way better than the latest block buster movie ...

 

Anyway, that's all well and good, I'm not adding much value reposting his stuff, so I'd just like to improve on his deployment recommendation.

Instead of adding a script reference to the master page and then inserting a content editor region to paste the JavaScript in, I would suggest using the JQuery Script Manager:

 

So the idea is to use SharePoint Designer to register the control with the JavaScript. Note here to use the ScriptTemplate you'll have to grab my latest script manager control from here.

<cc1:jQueryManager ID="JQueryManager1" runat="server">        
<ScriptTemplate>
$(".ms-RadioText[title='All'] :checkbox").click(function(){
 var otherids = (this.id).substring(0, (this.id).length-2 );
 $("input[id^='"+otherids+"']").attr( "checked" , (this.checked)?"checked":"" );});
</ScriptTemplate>
</cc1:jQueryManager>

This will insert the JQuery Script Manager and declaratively add the JavaScript code to the page. This way you don't need to worry about the script resources or having multiple client side load functions.

How can you not love JQuery after seeing the power of the above code? it's just that awesome!

Monday, September 15, 2008 10:47:30 AM (E. Australia Standard Time, UTC+10:00)  #    Comments [0] - Trackback
code | JQuery | Sharepoint | Work

I've previously posted a demo that illustrated a tag cloud web part, I've now posted the code.

First let me warn you that the method I've used to get the tag list will not scale, so please disregard the TagBuilder method, you'll need to implement that yourself.

tagcloud

 

I've based this tag cloud control loosely on the tag cloud control from codeproject, I've refactored most of it, but have kept the maths behind generating a weighting.

 

Using the control is pretty simple, you just need to measure the tags and then pass in a collection of CloudItems:

 

//tagList is a dictionary with the tag and count
Dictionary<string, int> tagList = new Dictionary<string, int>();

foreach (string tag in tagList.Keys)
{
    CloudItem cloudItem = new CloudItem();
    cloudItem.Text = tag;
    cloudItem.Weight = tagList[tag];
    cloudItem.Href = "/SearchCenter/Pages/Results.aspx?k=tags:" + tag;
    Items.Add(cloudItem);
}

There are a number of ways to perform the measurement, if you were to count the number of times a tagged resource was accessed, you would end up with a heat map of popular items. Alternatively you could simply count up the number of times a tag has been used (I think this is the most common use, I've done it this way in my demo). In any case the exact implementation details have been left up to you.

Monday, September 15, 2008 9:32:34 AM (E. Australia Standard Time, UTC+10:00)  #    Comments [0] - Trackback
code | Sharepoint | Work
# Sunday, September 14, 2008

The web part that I'm presenting today is more of a building block, it doesn't do much on its own. It makes use of the JQuery Corners Plugin.

 

image

 

To set the corner types you can modify the Corner Type setting:

 

image

 

The above example will cause the following JavaScript to be output:

 

jQuery('cornerDiv').corner('tr 25px');
 

This web part makes use of the JQuery Script Manager that I've posted about previously.

 

As usual the source can be found here.

 

A screencast of the control in action can also be found here.

 

Sunday, September 14, 2008 9:02:49 AM (E. Australia Standard Time, UTC+10:00)  #    Comments [0] - Trackback
code | JQuery | Screencast | Sharepoint | Work
Statistics
Total Posts: 190
This Year: 3
This Month: 0
This Week: 0
Comments: 38