Adding a Simile Timeline to Community Server

Dec 11, 2007 21:17 · 727 words · 4 minutes read blogging c# code communityserver simile-timeline

In case you have visited this site recently, you may have noticed the cool timeline in the Blog Archives page. This is an amazing bit of Javascript that displays a any content you like on a long virtual sheet. Its kind of like those great “entire history of the world” posters that you grew up with. I found this after looking at Scott Hanselman’s web site a few days ago. I figured that I had plenty of time, so I did the same thing. It wasn’t very hard, but it wasn’t exactly brain dead easy either.

To start off, I went up to the source page for the project at MIT. The examples on there are great. The documentation is a bit basic, but most of your needs are covered. After searching around a bit, I found a few other articles that were helpful, including a couple from LifeCycle Solutions and Ryan Kanno. Then it was just a matter of trying it out.

First, I added the javascript tag on my Blog Archives page:

Further down I added a div where the timeline was actually going to go:

“my-timeline” style=“height: 450px; border: 1px solid #aaa; margin-right:20px;” />

Next I created a new .js file to hold my javascript. I think I will use this file for lots of other stuff, so I made a new namespace just for the timeline code. Here is the entire file:

   1:  var TECHNOVANGELIST = {};
2: TECHNOVANGELIST.TimeLine = function() {
3: var tl;
4: var resizeTimerID = null;
5:
6: return {
7:  
8: createTimeLine: function () {
9: var eventSource = new Timeline.DefaultEventSource();
10: var theme = Timeline.ClassicTheme.create();
11: theme.event.bubble.width=520;
12: theme.event.bubble.height=120;
13: var curdate = new Date()
14: var bandInfos = [
15: Timeline.createBandInfo({
16: eventSource: eventSource,
17: date: curdate.toGMTString(),
18: width: "80%",
19: intervalUnit: Timeline.DateTime.WEEK,
20: intervalPixels: 50
21: }),
22: Timeline.createBandInfo({
23: showEventText: false,
24: trackHeight: 0.5,
25: trackGap: 0.2,
26: eventSource: eventSource,
27: date: curdate.toGMTString(),
28: width: "20%",
29: intervalUnit: Timeline.DateTime.MONTH,
30: intervalPixels: 100
31: })
32: ];
33: bandInfos[1].syncWith = 0;
34: bandInfos[1].highlight = true;
35: bandInfos[1].eventPainter.setLayout(bandInfos[0].eventPainter.getLayout());
36: tl = Timeline.create(document.getElementById("my-timeline"), bandInfos);
37: Timeline.loadXML(http://technovangelist.com/BlogTimelineSource.ashx,
function(xml, url) { eventSource.loadXML(xml, url); });
38: },
39:
40: onResize: function() {
41: if (resizeTimerID == null) {
42: resizeTimerID = window.setTimeout(function() {
43: resizeTimerID = null;
44: tl.layout();
45: }, 500);
46: }
47: }
48: };
49: } ();

Back in the Blog Archives page, I added the pointer to that js file:

<CSControl:Script src="../Common/TVLIB.js" runat="server" />
<script type="text/javascript">
   window.onload=TECHNOVANGELIST.TimeLine.createTimeLine;
   window.onresize=TECHNOVANGELIST.TimeLine.onResize;
</script>

You can try that out to see if it works so far, but your eventsource isn’t working yet. I have that pointing to a BlogTimelineSource.ashx which we haven’t created…yet. So here is the full file for BlogTimelineSource.ashx:

   1:  <%@ WebHandler Language="C#" Class="BlogTimeLineSource" Debug="true" %>
2: 
3: using System;
4: using System.Web;
5: using CommunityServer.Blogs.Controls;
6: using CommunityServer.Blogs.Components;
7: using System.Collections.Generic;
8: using CommunityServer.Components;
9: 
10: public class BlogTimeLineSource : IHttpHandler {
11:
12: public void ProcessRequest (HttpContext context) {
13: context.Response.ContentType = "text/xml";
14: context.Response.Write("<data>");
15: BlogThreadQuery query;
16: query = BlogThreadQuery.CreateNewAggregateQuery();
17:
18: query.PostConfig = BlogPostConfig.IsAggregated;
19: query.PageIndex = 0;
20: query.PageSize = 5000;
21: query.IncludeCategories = true;
22: query.BlogPostType = BlogPostType.Post | BlogPostType.Article;
23: 
24: ThreadSet ts = WeblogPosts.GetBlogThreads(query);
25: 
26: foreach (WeblogPost p in ts.Threads)
27: {
28: context.Response.Write("<event start="" + p.PostDate + "" link=""
+ p.ViewPostURL + "" title="" + p.Subject + "">");
29: context.Response.Write(context.Server.HtmlEncode(p.ForceExcerpt) + "</event>");
30: }
31: context.Response.Write("</data>");
32: }
33:
34: public bool IsReusable {
35: get {
36: return false;
37: }
38: }
39: 
40: }
At this point you run into a problem. The ashx file probably can't be found still. Its there, but Community Server doesn't know about it yet, so you may have to modify you SiteUrls_Override.config. I just added the following in an <override> block:
    <location name="BlogTimeLineSource" themeDir="common"  path="/" >
      <url name = "BlogTimelineSource"  path="/BlogTimelineSource.ashx" 
              pattern="/BlogTimelineSource.ashx" physicalPath="##themeDir##" 
              vanity="{2}" page="BlogTimelineSource.ashx"/>
    </location>

That’s it!! The toughest parts for me were trying to figure out how to reference the javascript file on a CS site, figuring out Javascript namespaces, and then doing the query in the ashx file. Then I spent a while tweaking the look…changing the height (though its referenced as width) of the bands and changing the size of the popup. Let me know if this is useful for you…