Creating a Calendar for the Events Calendar

Topics: General, Standard packages, XSLT
Aug 19, 2011 at 5:58 PM

I'm customizing the Events module, and I was looking for suggestions on creating a calendar for these.

I'd like a full calendar something like an Outlook Calendar. It'll look something like this with events:

http://www.bytecyclist.com/SourceCode/jMonthCalendar/1.3.0-beta/Demo.html

My two options are:

  1. Use the .Net Calendar Control and somehow get events to the Calendar. (I guess I'd use an ascx control)
  2. Create a calendar control myself and use the GetEventsXML Data to populate it.

I'd love suggestions on how to do it. I wouldn't mind contributing to the community on how I accomplished it once done, as well...

Thanks in advance...

Coordinator
Aug 29, 2011 at 11:51 AM

I saw someone use http://arshaw.com/fullcalendar/ to make a calendar on the public website, but I'm not familiar with the implementation details. But it looks worth checking out.

Aug 30, 2011 at 4:03 AM

atomiton,

mawtex sent me an email about this post.  I was able to create a "calendar" view using this module using the link that he mentioned above.  I am traveline for work right now and working on another client's request.  I will try to post how I was able to accomplish this sometime this week.  There is one issue I am working through right now.  I have added some elements for repeating days and I need to update the xslt view to query the events and displaying them correctly.

Aug 30, 2011 at 8:56 PM

Thanks robaford.

For now, I've implemented a .Net Calendar Control, but it would be nice for an integrated solution. I'll share the control's code here when I'm done.

Sep 4, 2011 at 4:02 AM

atomiton,

I tried to upload the information for the changes but I keep getting an error when trying to post the info.  The error message does not provide any useful information so I have no idea why it will not accept my post.  I will try to send the info via email.

Coordinator
Sep 5, 2011 at 7:37 AM

Robert, I'm sorry you are running into issues with this forum. It is managed by CodePlex so I can't even promise you it will be fixed.

Here is the text Robert mailed me - broken into two posts:


atominton and mawtex,

This week was kind of crazy.  I was able to get some time tonight to put together some information about getting the integrated calendar.  As mawtex mentioned my solutions is based upon the javascript callendar by Adam Shaw (fullcalendar, http://arshaw.com/fullcalendar/).  One thing to mention is that I started this process a little while back and unfortunately I was a bad developer and did not document all the changes that I made.  I believe that I have everything documented now but I may have missed a thing or two.  If you have any questions or issues let me know.  Below are the changes that I remember making.

Added the following files from the fullcalendar solution to the path: \frontend\composite\community\eventcalendar\fullcalendar\

fullcalendar.css, fullcalendar.js, fullcalendar.min.js, fullcalendar.print.js, gcal.js

I believe that I also made this change but I cannot remember if it was part of the base C1 install, \frontend\scripts\jquery\

jquery-1.5.2.min.js, jquery-ui-1.8.11.custom.min.js

That should be the end of the support files.  Next comes the configuration changes.  One of the requirements that I had for this was to create a basic repeating event process.  My client wanted to be able to create an event that spans a four week time period that but only occurs on certain days at certain times without needing to create multiple events.  All the events in the calendar need to link to the same event entry.  The start of providing this functionality was modifying the page datafolder entry for composite.community.eventcalendar.event.

I added the following fields as boolean datatype, Everyday, Sunday, Monday, Tuesday, Wednesday, Thuesday, Friday, Saturday.

The modifield form markup is below

<cms:formdefinition xmlns:cms="http://www.composite.net/ns/management/bindingforms/1.0" xmlns="http://www.composite.net/ns/management/bindingforms/std.ui.controls.lib/1.0" xmlns:f="http://www.composite.net/ns/management/bindingforms/std.function.lib/1.0">
  <cms:bindings>
    <cms:binding name="Title" type="System.String" optional="true" />
    <cms:binding name="Location" type="System.Guid" optional="true" />
    <cms:binding name="StartTime" type="System.DateTime" optional="true" />
    <cms:binding name="EndTime" type="System.DateTime" optional="true" />
    <cms:binding name="NumberOfSeats" type="System.Int32" optional="true" />
    <cms:binding name="SignupDeadline" type="System.DateTime" optional="true" />
    <cms:binding name="ShortDescription" type="System.String" optional="true" />
    <cms:binding name="Description" type="System.String" optional="true" />
    <cms:binding name="SignupConfiguration" type="System.Guid" optional="true" />
    <cms:binding name="Everyday" type="System.Boolean" optional="false" />
    <cms:binding name="Sunday" type="System.Boolean" optional="true" />
    <cms:binding name="Monday" type="System.Boolean" optional="true" />
    <cms:binding name="Tuesday" type="System.Boolean" optional="true" />
    <cms:binding name="Wednesday" type="System.Boolean" optional="true" />
    <cms:binding name="Thursday" type="System.Boolean" optional="true" />
    <cms:binding name="Friday" type="System.Boolean" optional="true" />
    <cms:binding name="Saturday" type="System.Boolean" optional="true" />
    <cms:binding name="PublicationStatus" type="System.String" optional="true" />
    <cms:binding name="CultureName" type="System.String" optional="true" />
    <cms:binding name="SourceCultureName" type="System.String" optional="true" />
    <cms:binding name="Id" type="System.Guid" optional="true" />
    <cms:binding name="PageId" type="System.Guid" optional="true" />
  </cms:bindings>
  <cms:layout>
    <cms:layout.label>
      <cms:read source="Title" />
    </cms:layout.label>
    <TabPanels PreSelectedIndex="0">
      <PlaceHolder Label="General">
        <FieldGroup Label="Information">
          <TextBox Label="Event title" Help="The title of the event.">
            <TextBox.Text>
              <cms:bind source="Title" />
            </TextBox.Text>
          </TextBox>
          <KeySelector Label="Location" Help="Where the event is taking place." OptionsKeyField="Key" OptionsLabelField="Label" Required="false">
            <KeySelector.Selected>
              <cms:bind source="Location" />
            </KeySelector.Selected>
            <KeySelector.Options>
              <f:StaticMethodCall Type="&lt;t n=&quot;Composite.Plugins.Functions.WidgetFunctionProviders.StandardWidgetFunctionProvider.DataReference.NullableDataReferenceSelectorWidgetFunction`1, Composite, Version=2.1.4087.22991, Culture=neutral, PublicKeyToken=null&quot;&gt;&#xD;&#xA;  &lt;t n=&quot;DynamicType:Composite.Community.EventCalendar.EventLocation&quot; /&gt;&#xD;&#xA;&lt;/t&gt;" Method="GetOptions" Parameters="DynamicType:Composite.Community.EventCalendar.EventLocation" />
            </KeySelector.Options>
          </KeySelector>
          <TextArea Label="Short description" Help="A short description for this event.">
            <TextArea.Text>
              <cms:bind source="ShortDescription" />
            </TextArea.Text>
          </TextArea>
        </FieldGroup>
        <FieldGroup Label="Date and Time">
          <DateTimeSelector Label="Start time" Help="The date and time the event start">
            <DateTimeSelector.Date>
              <cms:bind source="StartTime" />
            </DateTimeSelector.Date>
          </DateTimeSelector>
          <DateTimeSelector Label="End time" Help="The date and time the vent ends">
            <DateTimeSelector.Date>
              <cms:bind source="EndTime" />
            </DateTimeSelector.Date>
          </DateTimeSelector>
        </FieldGroup>
      </PlaceHolder>
      <PlaceHolder Label="Signup">
        <FieldGroup Label="Signup Settings">
          <TextBox Label="Number of seats" Help="The maximum number of available seats for this event." Type="Integer">
            <TextBox.Text>
              <cms:bind source="NumberOfSeats" />
            </TextBox.Text>
          </TextBox>
          <DateTimeSelector Label="Signup deadline" Help="Signups will not be possible past this deadline">
            <DateTimeSelector.Date>
              <cms:bind source="SignupDeadline" />
            </DateTimeSelector.Date>
          </DateTimeSelector>
          <KeySelector Label="Signup settings" Help="The settings to use for signup. If none is selected, signup is not available." OptionsKeyField="Key" OptionsLabelField="Label" Required="false">
            <KeySelector.Selected>
              <cms:bind source="SignupConfiguration" />
            </KeySelector.Selected>
            <KeySelector.Options>
              <f:StaticMethodCall Type="&lt;t n=&quot;Composite.Plugins.Functions.WidgetFunctionProviders.StandardWidgetFunctionProvider.DataReference.NullableDataReferenceSelectorWidgetFunction`1, Composite, Version=2.1.4087.22991, Culture=neutral, PublicKeyToken=null&quot;&gt;&#xD;&#xA;  &lt;t n=&quot;DynamicType:Composite.Community.EventCalendar.EventSignupConfiguration&quot; /&gt;&#xD;&#xA;&lt;/t&gt;" Method="GetOptions" Parameters="DynamicType:Composite.Community.EventCalendar.EventSignupConfiguration" />
            </KeySelector.Options>
          </KeySelector>
        </FieldGroup>
      </PlaceHolder>
      <PlaceHolder Label="Repeating">
        <FieldGroup Label="Everyday">
          <CheckBox Label="Everyday" Help="Flag that tells the process that when the start and end dates are different whether each day in the range is part of the event.">
            <CheckBox.Checked>
              <cms:bind source="Everyday" />
            </CheckBox.Checked>
          </CheckBox>
        </FieldGroup>  
        <FieldGroup Label="Individual Days">
          <CheckBox Label="Sunday" Help="When the start and end dates are different this value will identify that Sunday within the date range are part of the event.">
            <CheckBox.Checked>
              <cms:bind source="Sunday" />
            </CheckBox.Checked>
          </CheckBox>
          <CheckBox Label="Monday" Help="When the start and end dates are different this value will identify that Monday within the date range are part of the event.">
            <CheckBox.Checked>
              <cms:bind source="Monday" />
            </CheckBox.Checked>
          </CheckBox>
          <CheckBox Label="Tuesday" Help="When the start and end dates are different this value will identify that Tuesday within the date range are part of the event.">
            <CheckBox.Checked>
              <cms:bind source="Tuesday" />
            </CheckBox.Checked>
          </CheckBox>
          <CheckBox Label="Wednesday" Help="When the start and end dates are different this value will identify that Wednesday within the date range are part of the event.">
            <CheckBox.Checked>
              <cms:bind source="Wednesday" />
            </CheckBox.Checked>
          </CheckBox>
          <CheckBox Label="Thursday" Help="When the start and end dates are different this value will identify that Thursday within the date range are part of the event.">
            <CheckBox.Checked>
              <cms:bind source="Thursday" />
            </CheckBox.Checked>
          </CheckBox>
          <CheckBox Label="Friday" Help="When the start and end dates are different this value will identify that Friday within the date range are part of the event.">
            <CheckBox.Checked>
              <cms:bind source="Friday" />
            </CheckBox.Checked>
          </CheckBox>
          <CheckBox Label="Saturday" Help="When the start and end dates are different this value will identify that Saturday within the date range are part of the event.">
            <CheckBox.Checked>
              <cms:bind source="Saturday" />
            </CheckBox.Checked>
          </CheckBox>
        </FieldGroup> 
      </PlaceHolder>  
      <XhtmlEditor Label="Description" Help="A HTML formatted long description of the event." ClassConfigurationName="common">
        <XhtmlEditor.Xhtml>
          <cms:bind source="Description" />
        </XhtmlEditor.Xhtml>
      </XhtmlEditor>
    </TabPanels>
  </cms:layout>
</cms:formdefinition>

(continued)

Coordinator
Sep 5, 2011 at 7:37 AM

(continued)

Next comes the XSLT Function to create the visual function. First off, I created a function in the path XSLT Functions\Composite\Community\EventCalendar\Layout called EventCalendarView. It started out as an exact copy of the EventList function in the same path. Now the EventList function function uses a c# function to provide its information and since I am not able to modify it this function does not include any of our new fields thus making the function invalid for my use.  Because of this I removed the function call to the GetEvents function and then added the standard GetEventXML function.  I then selected all the available fields so that the would be available to my XSLT function.  Below is the code that I put into the function.

  <xsl:stylesheet version="1.0" 
  xmlns="http://www.w3.org/1999/xhtml"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
  exclude-result-prefixes="xsl in lang csharp" 
  xmlns:in="http://www.composite.net/ns/transformation/input/1.0" 
  xmlns:lang="http://www.composite.net/ns/localization/1.0" 
  xmlns:f="http://www.composite.net/ns/function/1.0"
  xmlns:csharp="http://c1.composite.net/sample/csharp" 
  xmlns:msxsl="urn:schemas-microsoft-com:xslt">
    
  <xsl:variable name="ShowHours" select="/in:inputs/in:param[@name='ShowHours']='true'" />
  <xsl:variable name="Events" select="/in:inputs/in:result[@name='GetEventXml']/Event" />
  <xsl:variable name="Locations" select="/in:inputs/in:result[@name='GetEventLocationXml']/EventLocation" />
  
  <xsl:template match="/">
    <html>
      <head>
        <link rel="stylesheet" type="text/css" href="~/Frontend/Composite/Community/EventCalendar/Styles.css" id="eventcalendarcss" />
        <link rel="stylesheet" type="text/css" media="all" href="~/Frontend/Composite/Community/EventCalendar/FullCalendar/fullcalendar.css" />
        <link rel="stylesheet" type="text/css" media="print" href="~/Frontend/Composite/Community/EventCalendar/FullCalendar/fullcalendar.print.css" />
        <script type='text/javascript' src='~/Frontend/Scripts/jquery/jquery-1.5.2.min.js'></script>
        <script type='text/javascript' src='~/Frontend/Scripts/jquery/jquery-ui-1.8.11.custom.min.js'></script>
        <script type='text/javascript' src='~/Frontend/Composite/Community/EventCalendar/FullCalendar/fullcalendar.min.js'></script>
      
        <script type='text/javascript'>
        $(document).ready(function() {
      
        var date = new Date();
        var d = date.getDate();
        var m = date.getMonth();
        var y = date.getFullYear();
        
        $('#calendar').fullCalendar({
            header: {
            left: 'prev,next today',
            center: 'title',
            right: 'month,agendaWeek,agendaDay'
          },
          editable: true,
          events: [
            <xsl:apply-templates select="$Events" />
            {
              title: 'dummy',
              start: new Date(2000, 1, 1),
              end: new Date(2000, 1, 1),
              url: '/'
            }
          ]
        });
        
      });
    
    </script>
      </head>
      <body>   
        <div id='calendar'></div>
      </body>
    </html>
  </xsl:template>
  
  
  <xsl:template match="Event">
    <xsl:variable name="url" select="csharp:CreateURL(@PageId.UrlTitle, @Id)" />
    <xsl:if test="@Everyday='true'">
      <xsl:if test="(contains(@StartTime,'T00:00'))">
        {
          title: '<xsl:value-of select="@Title" />',
          start: new Date('<xsl:value-of select="@StartTime" />'),
          end: new Date('<xsl:value-of select="@EndTime" />'),
          url: '<xsl:value-of select="$url" />'
        },
      </xsl:if>
      <xsl:if test="not(contains(@StartTime,'T00:00'))">
        {
          title: '<xsl:value-of select="@Title" />',
          start: new Date('<xsl:value-of select="@StartTime" />'),
          end: new Date('<xsl:value-of select="@EndTime" />'),
          allDay: false,
          url: '<xsl:value-of select="$url" />'
        },
      </xsl:if>
    </xsl:if>
    <xsl:if test="@Everyday='false'">
      <xsl:call-template name="multiDays">
        <xsl:with-param name="title" select="@Title"/>
        <xsl:with-param name="url" select="$url"/>
        <xsl:with-param name="count" select="csharp:DateDiffInDays(@StartTime,@EndTime)"/>
        <xsl:with-param name="startdate" select="@StartTime"/>
        <xsl:with-param name="enddate" select="concat(concat(substring-before(@StartTime,'T'),'T'),substring-after(@EndTime,'T'))"/>
        <xsl:with-param name="sunday" select="@Sunday"/>
        <xsl:with-param name="monday" select="@Monday"/>
        <xsl:with-param name="tuesday" select="@Tuesday"/>
        <xsl:with-param name="wednesday" select="@Wednesday"/>
        <xsl:with-param name="thursday" select="@Thursday"/>
        <xsl:with-param name="friday" select="@Friday"/>
        <xsl:with-param name="saturday" select="@Saturday"/>
      </xsl:call-template>
    </xsl:if>
  </xsl:template>
  
  <xsl:template name="multiDays">
    <xsl:param name="title" />
    <xsl:param name="url" />
    <xsl:param name="count" select="1"/>
    <xsl:param name="startdate" />
    <xsl:param name="enddate" />
    <xsl:param name="sunday" />
    <xsl:param name="monday" />
    <xsl:param name="tuesday" />
    <xsl:param name="wednesday" />
    <xsl:param name="thursday" />
    <xsl:param name="friday" />
    <xsl:param name="saturday" />

    <xsl:if test="$count > 0">
      <xsl:variable name="valid" select="csharp:Valid($startdate,$sunday,$monday,$tuesday,$wednesday,$thursday,$friday,$saturday)" />
      <xsl:if test="$valid='true'">
        {
          title: '<xsl:value-of select="$title" />',
          start: new Date('<xsl:value-of select="$startdate" />'),
          <xsl:if test="not(contains($startdate,'T00:00')) and not(contains($enddate,'T00:00'))">
            end: new Date('<xsl:value-of select="$enddate" />'),
            allDay: false,
          </xsl:if>  
          url: '<xsl:value-of select="$url" />',
          allDay: false
        },
      </xsl:if>
      <xsl:call-template name="multiDays">
        <xsl:with-param name="title" select="$title" />
        <xsl:with-param name="url" select="$url" />
        <xsl:with-param name="count" select="$count - 1" />
        <xsl:with-param name="startdate" select="csharp:DateAdd($startdate)" />
        <xsl:with-param name="enddate" select="csharp:DateAdd($enddate)" />
        <xsl:with-param name="sunday" select="$sunday" />
        <xsl:with-param name="monday" select="$monday" />
        <xsl:with-param name="tuesday" select="$tuesday" />
        <xsl:with-param name="wednesday" select="$wednesday" />
        <xsl:with-param name="thursday" select="$thursday" />
        <xsl:with-param name="friday" select="$friday" />
        <xsl:with-param name="saturday" select="$saturday" />
      </xsl:call-template>
    </xsl:if>
  </xsl:template>
    
  <msxsl:script implements-prefix="csharp" language="C#"> 
      <![CDATA[
        public int DateDiffInDays(DateTime StartDate, DateTime EndDate)
        {
          return EndDate.Subtract(StartDate).Days;
        }

        public string CreateURL(string UrlTitle, string EventId)
        {
          string url = UrlTitle + ".aspx?eventid=" + EventId;
          return url;
        }

        public DateTime DateAdd(DateTime EvalDate)
        {
          return EvalDate.AddDays(1);
        }

        public string Valid(DateTime EvalDate, string Sunday, string Monday, string Tuesday, string Wednesday, string Thursday, string Friday, string Saturday)
        {
          string valid = "false";

          if(EvalDate.DayOfWeek==DayOfWeek.Sunday && Sunday=="true")
          {
            valid="true";
          }
          if(EvalDate.DayOfWeek==DayOfWeek.Monday && Monday=="true")
          {
            valid="true";
          }
          if(EvalDate.DayOfWeek==DayOfWeek.Tuesday && Tuesday=="true")
          {
            valid="true";
          }
          if(EvalDate.DayOfWeek==DayOfWeek.Wednesday && Wednesday=="true")
          {
            valid="true";
          }
          if(EvalDate.DayOfWeek==DayOfWeek.Thursday && Thursday=="true")
          {
            valid="true";
          }
          if(EvalDate.DayOfWeek==DayOfWeek.Friday && Friday=="true")
          {
            valid="true";
          }
          if(EvalDate.DayOfWeek==DayOfWeek.Saturday && Saturday=="true")
          {
            valid="true";
          }
          return valid;
        }
      ]]>
    </msxsl:script>
</xsl:stylesheet>

One thing to note is that the "repeating" feature works but is not best to be performed in the manner that I implemented. It works good for small numbers of events or events that do not have a lot of repeating days. It is best to perform this in the c# function for performance reasons. The reason for this is that the C# function is compiled and can create the repeating events faster. Also it is important to note that the calendar creates the events based upon a JSON data feed so we have to convert the events created in C1 to a JSON format and that is mostly what this XSLT function does.

I hope that this helps.  If you have any questions or issues please let me know.

Sep 5, 2011 at 7:50 AM

For managing recurring events you should look at some standard implementation of the iCal standard (http://en.wikipedia.org/wiki/ICalendar). I can recommend DDay.iCal for .Net (http://sourceforge.net/projects/dday-ical/) which aims for comparability with major calendar applications and you also get exporting to ics files for free for importing in ie Google Calendar or Outlook.

Also remember to mark up your html semantics so it support the hCalendar format (http://en.wikipedia.org/wiki/HCalendar). This makes it possible for search engines and browser plugins to extract the event information in a meaningful manner

Sep 7, 2011 at 6:38 AM

Wow! I can't wait to try this out!

Sep 13, 2011 at 8:17 PM
Edited Sep 13, 2011 at 8:19 PM

I can't wait to try this.  Looks Great!

I have a question.  I am currently trying to just list events, which works just fine.  How can I get the function to group the events by Month/Year.  I tried to do this using Keys and variables but I think my problems were the StartDate and Breaking down the date (but not sure).  For example:

January 2011

   January 1, 2011  Event 1

   January 2, 2011 Event 2

Febuary 2011

 February 1, 2011 Event 3

 February 2, 2011 Event 4

and so on...

 

Here is what I have so far that worked:

 

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" exclude-result-prefixes="xsl in df msxsl user"
	xmlns:in="http://www.composite.net/ns/transformation/input/1.0"
	xmlns="http://www.w3.org/1999/xhtml"
	xmlns:df="#dateExtensions"
	xmlns:msxsl="urn:schemas-microsoft-com:xslt"
	xmlns:user="urn:my-scripts"
>

	<xsl:param name="displayMode" select="/in:inputs/in:param[@name='DisplayMode']" />

	<msxsl:script language="C#" implements-prefix="user">
	<msxsl:assembly name="System.Web"/>
	<![CDATA[
		public int CompareDate(string date)
		{
			return DateTime.Compare(DateTime.Parse(date),  DateTime.Now);
		}
	]]>
	</msxsl:script>

	<xsl:template match="/">
		<html>
			<head>
				<link rel="stylesheet" type="text/css" href="~/Frontend/Composite/Lists/EventCalendar/Style.css" />
			</head>
			<body>

				<xsl:variable name="eventlist">
					<xsl:choose>
						<xsl:when test="$displayMode='true'">
							<xsl:copy-of select="/in:inputs/in:result[@name='GetCalendarXml']/*[user:CompareDate(@EndDate) &gt; 0]" />
						</xsl:when>
						<xsl:otherwise>
							<xsl:copy-of select="/in:inputs/in:result[@name='GetCalendarXml']/*[user:CompareDate(@EndDate) &lt; 0]" />
						</xsl:otherwise>
					</xsl:choose>
				</xsl:variable>

				<xsl:choose>
					<xsl:when test="count(msxsl:node-set($eventlist)/*)&gt;0">
						<xsl:apply-templates select="msxsl:node-set($eventlist)/*" />
					</xsl:when>
					<xsl:otherwise>
						<p>There are no Event entries published yet.</p>
					</xsl:otherwise>
				</xsl:choose>

			</body>
		</html>
	</xsl:template>

	<xsl:template match="Calendar">
		<div class="ListItem">
			<div>
				<a href="~/Renderers/Page.aspx?DateView={@Id}&amp;pageId={@PageId}">
					<xsl:value-of select="@Title" />
				</a>
			</div>
			<small class="StartDate">
				<xsl:value-of select="df:ShortDateFormat(@StartDate)" />
			</small>
			 - 
			<small class="EndDate">
				<xsl:value-of select="df:ShortDateFormat(@EndDate)" />
			</small>
		</div>
		<div>
			<xsl:value-of select="@ShortDescription" />
		</div>
	</xsl:template>

</xsl:stylesheet>
Coordinator
Sep 14, 2011 at 11:02 AM
c2w wrote:

I can't wait to try this.  Looks Great!

I have a question.  I am currently trying to just list events, which works just fine.  How can I get the function to group the events by Month/Year.  I tried to do this using Keys and variables but I think my problems were the StartDate and Breaking down the date (but not sure).  For example:

January 2011

   January 1, 2011  Event 1

   January 2, 2011 Event 2

Febuary 2011

 February 1, 2011 Event 3

 February 2, 2011 Event 4

and so on...

Here is what I have so far that worked:

Hello,

Consider next example:

1. Create new XSLT, f.e. named as Composite.Lists.EvantCalendar.ListGoupedByYearMonth

2. Add two Function calls: Composite.Lists.EventCalendar.GetEventCalendarXml and Composite.XSLT.Extentions.DateFormating

3. Template tab:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:in="http://www.composite.net/ns/transformation/input/1.0" xmlns="http://www.w3.org/1999/xhtml" xmlns:df="#dateExtensions" exclude-result-prefixes="xsl in df">
  <xsl:variable name="eventlist" select="/in:inputs/in:result[@name='GetEventCalendarXml']" />
  <xsl:key name="by-Year" match="EventCalendar" use="df:Year(@StartDate)" />
  <xsl:key name="by-Month" match="EventCalendar" use="df:Month(@StartDate)" />
  <xsl:template match="/">
    <html>
      <head>
        <link rel="stylesheet" type="text/css" href="~/Frontend/Composite/Lists/EventCalendar/Style.css" />
      </head>
      <body>
        <xsl:for-each select="$eventlist/EventCalendar[generate-id(.)=generate-id(key('by-Year',df:Year(@StartDate)))]">
          <xsl:variable name="year" select="df:Year(@StartDate)" />
          <xsl:for-each select="$eventlist/EventCalendar[generate-id(.)=generate-id(key('by-Month',df:Month(@StartDate))[df:Year(@StartDate)=$year])]">
            <xsl:sort data-type="number" select="df:Month(@StartDate)" />
            <xsl:variable name="monthNumber" select="df:Month(@StartDate)" />
            <xsl:variable name="month" select="df:LongMonthName($monthNumber)" />
            <h1>
              <xsl:value-of select="$month" />&#160;<xsl:value-of select="$year" />
            </h1>
            <ul>
              <xsl:for-each select="key('by-Month',$monthNumber)[df:Year(@StartDate)=$year]">
                <li>
                  <xsl:value-of select="df:LongDateFormat(@StartDate)" />-
                  <xsl:value-of select="@Title" />
                </li>
              </xsl:for-each>
            </ul>
          </xsl:for-each>
        </xsl:for-each>
      </body>
    </html>
  </xsl:template>
  
</xsl:stylesheet>

Sep 20, 2011 at 2:14 PM

c2w,

If you are in need of more flexible formatting for the grouping names you may want to add a c# function to do that formatting.  I have found it is much easier to use c# for formatting than XSLT function (though I am also a c# developer).