Tuesday, September 1, 2009

Web Part wrapper for the Google Dynamic Feed Control

If this is out there, 2 minutes of searching couldn’t find it. Interesting little exercise even if it is out there.

The out of the box SharePoint 2007 RSS Viewer web part is pretty lame. It is pretty much the Xml Web part with 300+ lines of ready made XSL. This might just be my opinion, but XSL is only really interesting the first time you do something with it. After that, you can have it back – especially when it comes to debugging it.

So I was looking around for a pinch hitter for the out of the box RSS web part and came across the Google Dynamic Feed Control. This is what it looks like in vertical mode with the default CSS applied:

dynamicfeed

Works well. Looks good enough. Free. What more could one ask for? How about the following advantages over the RSS Viewer web part:

  • Can consume both RSS and Atom feeds.
  • SSL Friendly – can consume an HTTP feed from an HTTPS site without the annoying security warning dialog. This is actually a pretty important advantage if you are within an SSL site.
  • Aggregation – it can handle more than one feed.
  • Built in AJAX updates. Side bonus: It won’t cause script errors – specifically the infamous ASP.NET pendingCallbacks bug – if there is more than one instance on a page.
  • Superior UI and use of screen real estate.
  • Does not require XSL manipulation to change.
  • No half-baked loading bar graphic. Where did that thing come from anyways? If it played the Knight Rider theme while it loaded or a KITT sound effect, it would possibly have some value.

CRPERSPC

This javascript control is built on the Google Feeds API, and as with all of Google’s ‘free’ stuff, the integration point for this is within the client tier via javascript. This will make it easier for Google to steal your customers in the future. I like to joke around – but unfortunately that was not a joke. Having their API’s all javascript – and therefore in almost all cases from the client tier – is a brilliant move. But only for them – and maybe the rest of us who take advantage of their price points in the short term.

OK – digression phase complete. I set out to create a web part wrapper to make the incorporation of this control into a SharePoint site easer. The web part essentially generates the javascript required to initialize and render the control using the Google API.

Web Part Construction

Within the web part, there are essentially three main pieces:

  1. Create personalizable properties that allow the web part to be customized.
  2. Get the Google Ajax API and the Dynamic Feed Control scripts into the page.
  3. Render the client script that loads the control based on the configured properties and the containing HTML element (just a DIV).

Step 1: This is pretty standard web part stuff. Some of the customizable properties I created:

  • FeedURL – Allows the specification of an RSS/Atom feed. This can be a semicolon delimited list to show multiple feeds. I know - a crude way to do it – but we can save the custom editor for a rainy day.
  • PageSize – How many records to show.
  • DisplayTime – How many seconds to show the details of an item before moving on to the next one. The Dynamic Feed Control continuously cycles through the items in the list and displays the details of one item at a time.
  • CssUrl – the url of the stylesheet containing the classes used in the markup. The schema for the CSS is outlined here.

Step 2: The core Google javascript does not do well if it is not loaded into the page before content – or more importantly other scripts – are rendered. In other words, it needs to be in the HEAD section. This means that the normal means of doing this – using the regular Page.ClientScript.RegisterClientScriptBlock method – will not be good enough, since that loads scripts into the BODY section. One way to get script into the HEAD section is to add to the Page.Head.Controls collection. So here is the code to register the Google JSAPI core – and the Dynamic Feed Control:



Code Snippet



  1. protected virtual void RegisterScripts()
  2. {
  3. if (CanRender)
  4. {
  5. //add scripts to header - the registered block is used just as indication that we already
  6. // added the script to the page
  7. //google jsapi script does not do well if it is not already loaded into head section
  8. if (!Page.ClientScript.IsClientScriptBlockRegistered(this.GetType(), GoogleAjaxKey))
  9. {
  10. Page.ClientScript.RegisterClientScriptBlock(
  11. this.GetType(),
  12. GoogleAjaxKey,
  13. string.Empty);
  14. Page.Header.Controls.Add(new LiteralControl(string.Format(ScriptLinkTemplate,
  15. string.Format(GoogleAjaxUrl,
  16. HttpContext.Current.Request.Url.Scheme,
  17. string.IsNullOrEmpty(ApiKey)
  18. ? string.Empty
  19. : string.Format("?key={0}", ApiKey)))));
  20. }
  21. if (!Page.ClientScript.IsClientScriptBlockRegistered(this.GetType(), GoogleDynamicFeedKey))
  22. {
  23. Page.ClientScript.RegisterClientScriptBlock(
  24. this.GetType(),
  25. GoogleDynamicFeedKey,
  26. string.Empty);
  27. Page.Header.Controls.Add(new LiteralControl(string.Format(ScriptLinkTemplate,
  28. string.Format(GoogleDynamicFeedUrl,
  29. HttpContext.Current.Request.Url.Scheme))));
  30. }
  31. }
  32. \




Step 3: Rendering the script is just string manipulation. It is possible to get really fancy when building javascript dynamically within C#, but sometimes you can’t beat a good old fashioned StringBuilder. The most important thing to get right is the order – you do not want something to reference script that has not loaded yet or an object that has not yet been defined. So the general order here will be:

Body Load > Google Feeds Load > Dynamic Feed Control Load

which translates to (all javascript):

_spBodyOnLoadFunctionNames this allows us to add a function to be called when the SharePoint-rendered DOM is loaded

google.load('feeds'…) this loads the Google feeds api – used by the dynamic feed control

new GFdynamicFeedControl() creates the javascript object – it will do the rest

The rest of it is the dynamic generation of the options objects based on the configured property values (remember step 1?) Here is what I mean – actually pretty simple:



Code Snippet



  1. protected virtual string BuildFeedOptionsScript()
  2. {
  3. StringBuilder script = new StringBuilder();
  4. script.Append("var options = {");
  5. script.Append("stacked : true, ");
  6. script.Append("horizontal : false, ");
  7. script.AppendFormat("numResults : {0}, ",
  8. PageSize);
  9. script.AppendFormat("displaytime: {0}, ",
  10. DisplayTime * 1000);
  11. script.Append("fadeOutTime : 1000, ");
  12. script.Append("scrollOnFadeOut : true, ");
  13. script.AppendFormat("title : \"{0}\"",
  14. Page.Server.HtmlEncode(this.Title));
  15. script.Append("};");
  16. return script.ToString();
  17. \




That is pretty much the bulk of it. In the end you have yourself an RSS (and Atom) consuming web part that is superior to what you get out of the box.

The Visual Studio 2008 solution uses takes advantage of feature based web part deployment and uses STSDev2008 (you will need to install it if you want to build).

VS2008 Solution:

Just the WSP

1 comment:

  1. Chad,
    I hear you on the Google buy-in. Same goes for the Yahoo and Bing javascript solutions. You also miss search engines with this kind of lazy loading. That applies to the out of the box rss web part, too, though.
    The Page.Header.Controls usage is a great example for SharePoint Development. It's good to remember to use all of our asp.net options when the SharePoint ones don't fit the bill.
    Thanks,
    Tom

    ReplyDelete

 
© I caught you a delicious bass.
Back to top