Implementing jquery-week-calendar into a Dynamicweb-module

The other day, I needed a calendar to display all existing reservations for certain facilities. Earlier, I have used Telerik’s Scheduler-control – which is really great. However, the Telerik Scheduler-control does not play nicely with Dynamicweb CMS. Therefore, I decided to go hunting for another calendar-control.

As always, jQuery came to the rescue. A quick search on Google revealed several cool jQuery-implementations. But I quickly decided that the most interesting one was the jQuery Week Calendar. This one not only allows you to display your calendar events in a ‘real’ week calendar – it also allows you to configure everything from the layout to the different texts as well as date formats. You can find the source-files here: http://github.com/themouette/jquery-week-calendar. And you can also view a demo right here: http://jquery-week-calendar.googlecode.com/svn/trunk/jquery.weekcalendar/full_demo/weekcalendar_full_demo.html. The demo allows you to view existing reservations as well as add new ones and edit existing.

Please notice, that the original jQuery Week Calendar – developed by Rob Monie – has been forked to another project. I suggest that you download the latest source code from the new project – but also that you read the wiki in the old project. The reason for this is the fact that the old wiki has more information about how to configure the plugin.

This image displays a demo of the jquery week calendar

Screenshot from the jquery week calendar demo

After I made by decision, I started implementing the calendar into a Dynamicweb-module. First, I created a new project in Visual Studio. Then I included the jquery-week-calendar. I decided to place all of these files into Files/Templates/NemLejeScheduler/Calendar. I always prefer having my module-related JavaScript and CSS-files stored in the template-folder – that way, I know how to find them again.

After that, I added a new JavaScript-file called weekCalendarSettings.js. This file contains all of my different configuration settings:

 

// Event container
var eventData;

$(document).ready(function () {

    $('#calendar').weekCalendar({
        timeslotsPerHour: 1,
        height: function ($calendar) {
            return $(window).height() - $("h1").outerHeight();
        },
        eventRender: function (calEvent, $event) {
            if (calEvent.end.getTime() < new Date().getTime()) {
                $event.css("backgroundColor", "#aaa");
                $event.find(".time").css({ "backgroundColor": "#999", "border": "1px solid #888" });
            }
        },
        noEvents: function () {
            displayMessage("Der er ingen begivenheder i denne uge");
        },
        shortMonths: ["jan", "feb", "mar", "apr", "maj", "jun", "jul", "aug", "sep", "okt", "nov", "dec"],
        longMonths: ["januar", "februar", "marts", "april", "maj", "juni", "juli", "august", "september", "oktober", "november", "december"],
        longDays: ["Mandag", "Tirsdag", "Onsdag", "Torsdag", "Fredag", "Lørdag", "Søndag"],
        use24Hour: true,
        readonly: true,
        dateFormat: "d-M-Y",
        timeFormat: "H:i",
        timeSeparator: " - ",
        useShortDayNames: false,
        businessHours: (0, 24, false),
        buttonText: { today: "I dag" },
        data: eventData
    });

    function displayMessage(message) {
        $("#message").html(message).fadeIn();
    }

    $("<div id=\"message\" class=\"ui-corner-all\"></div>").prependTo($("body"));

});

The code is pretty straight forward, but there are one or two important remarks:

  • The eventData-object contains all events. I declare this at the top of my JavaScript, and instruct the jquery-week-calendar to use this data. The data will be rendered by the module later on. You can also decide to get all of your data from a URL instead.
  • In this project, I needed to make sure that all texts were in Danish. You can control all of the different texts by changing the shortMonths, longMonths and longDays-arrays. Also, you can change the time-format by changing use24Hour, dateFormat, timeFormat and timeSeparator.
  • In this project, I just needed to display the calendar events – there was no need to add new ones or change existing ones. Therefore I use readOnly: true to disable all editing.

You can find much more information on how to configure the jquery-week-calendar in the wiki: http://github.com/robmonie/jquery-week-calendar/wiki (please notice, that this is the old wiki – the old wiki contains more information than the new one located at this address: http://github.com/themouette/jquery-week-calendar/wiki).

After I had created the calendar-settings, I needed a place to display my calendar. Therefore, I created a new template and stored this into Files/Templates/NemLejeScheduler.

<script type='text/javascript'>
           eventData = {events: [
           <!--@Scheduler_EventData-->
           ]};
</script>
<h1>
    <!--@Scheduler_Name-->
</h1>
<p>
    <!--@Scheduler_Description-->
</p>
<h2>
    Fakta:</h2>
<table cellpadding="3" cellspacing="6">
    <tr>
        <td>
            Adresse:
        </td>
        <td>
            <!--@Scheduler_Address-->
        </td>
    </tr>
    <tr>
        <td>
            Postnummer:
        </td>
        <td>
            <!--@Scheduler_ZipCode-->
        </td>
    </tr>
    <tr>
        <td>
            By:
        </td>
        <td>
            <!--@Scheduler_City-->
        </td>
    </tr>
    <tr>
        <td>
            Max antal personer:
        </td>
        <td>
            <!--@Scheduler_MaxPersonReservationLimit-->
        </td>
    </tr>
    <tr>
        <td>
            Max reservationstid:
        </td>
        <td>
            <!--@Scheduler_MaxTimeReservationLimit-->
        </td>
    </tr>
    <tr>
        <td>
            Leje pr. dag (beboer):
        </td>
        <td>
            <!--@Scheduler_RentPerDay-->
        </td>
    </tr>
    <tr>
        <td>
            Depositum (beboer):
        </td>
        <td>
            <!--@Scheduler_Deposit-->
        </td>
    </tr>
    <tr>
        <td>
            Afbestillingsgebyr:
        </td>
        <td>
            <!--@Scheduler_CancellationFee-->
        </td>
    </tr>
</table>
<br />
<h2>
    Kalender</h2>
<div id='calendar'>
</div>

This template is really simple. Again, however, there are some important thing to notice:

  • I have included a small piece of JavaScript. Here, I will insert the calendar event data.
  • I have created an empty <div> at the bottom. This will contain the calendar.

Now I just need to create a small module, that will grab some data, and render it.

using System;
using System.Linq;
using System.Text;
using Dynamicweb;
using Dynamicweb.Extensibility;
using Template = Dynamicweb.Templatev2.Template;

namespace NemLejeScheduler
{
 [AddInName("NemLejeScheduler")]
 public class Frontend : ContentModule
 {
 public override string GetContent()
 {
 // Load properties from paragraph settings
 Dynamicweb.Properties.LoadProperties();
 Properties.SetDefaultValue("NemLejeSchedulerTemplate", "NemLejeScheduler.html");
 var NemLejeSchedulerTemplate = new Template("NemLejeScheduler/" + Properties["NemLejeSchedulerTemplate"]);
 var departmentId = Convert.ToInt32(Properties["departmentId"]); // 97;
 var roomNumber = Convert.ToInt32(Properties["roomNumber"]); // 3;

 // Add all necessary Javascript and CSS
 Pageview.AddJavascript("http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js");
 Pageview.AddJavascript("http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.5/jquery-ui.min.js");
 Pageview.AddJavascript("/Files/Templates/NemLejeScheduler/calendar/libs/date.js");
 Pageview.AddJavascript("/Files/Templates/NemLejeScheduler/calendar/jquery.weekcalendar.js");
 Pageview.AddJavascript("/Files/Templates/NemLejeScheduler/calendar/weekCalendarSettings.js");
 Pageview.AddStylesheet("/Files/Templates/NemLejeScheduler/calendar/libs/css/smoothness/jquery-ui-1.8.css");
 Pageview.AddStylesheet("/Files/Templates/NemLejeScheduler/calendar/jquery.weekcalendar.css");

 // Initialize stringbuilder object - contains JSON
 var eventJS = new StringBuilder();

 // Retrieve information about the reservation object and output to the template
 using (NemLejeScheduler.OBOEntities oboentities = new NemLejeScheduler.OBOEntities()) {
 var information = (from l in oboentities.LejemaalLokale
 where l.Lejemaal == roomNumber && l.Afd == departmentId
 select l).FirstOrDefault();

 NemLejeSchedulerTemplate.SetTag("Scheduler_Name", information.navn);
 NemLejeSchedulerTemplate.SetTag("Scheduler_Address", information.adresse);
 NemLejeSchedulerTemplate.SetTag("Scheduler_ZipCode", information.postnr.ToString());
 NemLejeSchedulerTemplate.SetTag("Scheduler_City", information.bynavn);
 NemLejeSchedulerTemplate.SetTag("Scheduler_Squaremeters", information.Kvm.ToString());
 NemLejeSchedulerTemplate.SetTag("Scheduler_MaxTimeReservationLimit", information.MaxAntUdlDage.ToString());
 NemLejeSchedulerTemplate.SetTag("Scheduler_MaxPersonReservationLimit", information.MaxAntPersoner.ToString());
 NemLejeSchedulerTemplate.SetTag("Scheduler_RentPerDay", information.BeboerLejePrDag.ToString());
 NemLejeSchedulerTemplate.SetTag("Scheduler_Deposit", information.BeboerDepositum.ToString());
 NemLejeSchedulerTemplate.SetTag("Scheduler_CancellationFee", information.BeboerAfbestGebyr.ToString());
 NemLejeSchedulerTemplate.SetTag("Scheduler_RentPerDayOthers", information.AndreLejePrDag.ToString());
 NemLejeSchedulerTemplate.SetTag("Scheduler_DepositOthers", information.AndreDepositum.ToString());
 NemLejeSchedulerTemplate.SetTag("Scheduler_CancellationFeeOthers", information.AndreAfbestGebyr.ToString());
 NemLejeSchedulerTemplate.SetTag("Scheduler_Description", information.Beskrivelse);

 // Retrieve all existing reservations from the database - retrieve start-date, end-date, id and title
 var reservations = from rd in oboentities.ReservationsDetalje
 join r in oboentities.Reservation on rd.Reservationsnr equals r.Reservationsnr
 where rd.Afd == departmentId && rd.lejemaal == roomNumber
 select new
 {
 Start = rd.Start,
 End = rd.Slut,
 Id = r.Reservationsnr,
 Title = r.Beskrivelse
 };
 // Build JSON string
 foreach (var reservation in reservations)
 {
 eventJS.AppendFormat("{{\"id\": {0}, \"start\": \"{1}\", \"end\": \"{2}\", \"title\": \"{3}\"}},{4}", reservation.Id, reservation.Start.Value.ToString("s"), reservation.End.Value.ToString("s"), reservation.Title, Environment.NewLine);
 }

 // Output to template
 NemLejeSchedulerTemplate.SetTag("Scheduler_EventData", eventJS.ToString());
 }

 // And we're done....
 return NemLejeSchedulerTemplate.Output();
 }
 }
}

If you’re used to working with Dynamicweb-modules, you will know most of the code mentioned above. However, in this case, there are a couple of things to notice:

  • I register all JavaScript and CSS by using the Pageview.AddJavascript and the Pageview.AddStylesheet. This will make sure, that the JavaScript and the CSS are placed correctly in the HTML.
  • I then initialize a StringBuilder-object called eventJS. This will hold all event-data.
  • I then retrieve some general information about the reservation object. Note, that I have created a datamodel to enable me to use Linq. Please notice, that your datamodel connection settings will be stored in web.config. This can potentially lead to a conflict with Dynamicweb CMS, as Dynamicweb tends to update the web.config file – thereby erasing your fine work and crashing your module.
  • Finally, I retrieve all existing reservations from the datamodel. Of course, you will create your own datamodel containing your information. The important thing here is that you need to map information to four different fields: Id, Title, Start and End. In my case, I map the fields called Reservationsnr, Beskrivelse, Start and Slut (This means ‘End’ in Danish – and not…you know what…)
  • The information from the datamodel is then appended to the eventJS-string. It is important, that this string looks just like the following:
eventData = {events: [
           {"id": 2, "start": "2006-03-31T17:00:00", "end": "2006-04-02T11:59:00", "title": "Meeting"},
      ]};
  • Please notice the date-format in the above mentioned string. The jquery-week-calendar will not work unless you output the date this way. This is also the reason why I didn’t use the built-in DataContractJsonSerializer-class. Does anyone know of a smart way of handling date-formats in this class?

Finally, I just need paragraph-settings:


<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="NemLejeScheduler_Edit.aspx.cs" Inherits="NemLejeScheduler.NemLejeScheduler_Edit" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<%@ Register TagPrefix="dw" Namespace="Dynamicweb.Controls" Assembly="Dynamicweb.Controls" %>
<%@ Register TagPrefix="mc" Namespace="Dynamicweb.Admin.ModulesCommon" Assembly="Dynamicweb.Admin" %>
<%@ Import Namespace="Dynamicweb" %>
<%@ Import Namespace="Dynamicweb.Admin" %>
<%@ Import Namespace="Dynamicweb.Backend" %>

<input type="hidden" name="NemLejeScheduler_settings" value="roomNumber, departmentId, NemLejeSchedulerTemplate">
<dw:ModuleHeader ID="_moduleHeader" runat="server" ModuleSystemName="NemLejeScheduler" />

<tr id="_paragraphBleauPicasa">
 <td colspan="2">
 <fieldset style="margin: 5px;">
 <legend>
 <label style="vertical-align: middle;">
 <dw:TranslateLabel ID="TranslateLabel1" runat="server" Text="Settings" />
 </label>
 </legend>
 <table cellpadding="2" cellspacing="0">
 <tr>
 <td>
 <dw:TranslateLabel ID="TranslateLabel2" runat="server" Text="Template" />
 </td>
 <td>
 <%=Gui.FileManager(Prop.Values["NemLejeSchedulerTemplate"] != null ? Prop.Values["NemLejeSchedulerTemplate"].ToString() : "", "Templates/NemLejeScheduler/", "NemLejeSchedulerTemplate")%>
 </td>
 </tr>
 <tr>
 <td>
 <dw:TranslateLabel ID="TranslateLabel5" runat="server" Text="Afdelingsnummer" />
 </td>
 <td>
 <input type="text" runat="server" name="departmentId" id="departmentId" />
 </td>
 </tr>
 <tr>
 <td>
 <dw:TranslateLabel ID="TranslateLabel6" runat="server" Text="Lejemålsnummer" />
 </td>
 <td>
 <input type="text" runat="server" name="roomNumber" id="roomNumber" />
 </td>
 </tr>
 </table>
 </fieldset>
 </td>
</tr>
<%Translate.GetEditOnlineScript();%>

And the C#-code for the paragraph-settings:


using System;
using Dynamicweb;

namespace NemLejeScheduler
{
 public partial class NemLejeScheduler_Edit : System.Web.UI.Page
 {
 private const String DefaultNemLejeSchedulerTemplate = "NemLejeScheduler.html";
 private int _paragraphId;
 protected Dynamicweb.Properties Prop = new Dynamicweb.Properties();

 private bool IsNewParagraph
 {
 get
 {
 return !String.IsNullOrEmpty(Request.QueryString["ParagraphModuleSystemName"]);
 }
 }

 protected void Page_Load(object sender, EventArgs e)
 {
 _paragraphId = Base.ChkNumber(Request["ID"] ?? Request["ParagraphID"]);

 if (IsNewParagraph)
 {
 Prop.Values["NemLejeSchedulerTemplate"] = DefaultNemLejeSchedulerTemplate;
 }
 else
 {
 Prop = Base.GetParagraphModuleSettings(_paragraphId, true);
 if (Prop.Values["departmentId"] != null)
 {
 departmentId.Value = Prop.Values["departmentId"].ToString();
 }
 if (Prop.Values["roomNumber"] != null)
 {
 roomNumber.Value = Prop.Values["roomNumber"].ToString();
 }
 }
 }
 }
}

And voila….you’re done. Later on, I will create an example, that will enable you to add and edit reservations.

Thanks to the people behind this great plugin!

Advertisements

One thought on “Implementing jquery-week-calendar into a Dynamicweb-module

  1. Nice…. just some comments on correctly implementing the start of week day, and implementing week numbers

    1. to start on mondays and not have wrong day names:

    firstDayOfWeek:1,
    longDays: [“Søndag”, “Mandag”, “Tirsdag”, “Onsdag”, “Torsdag”, “Fredag”, “Lørdag”],

    Yes, its Danish, but note that just because I set monday(mandag), as the first day of the week, I should still have my daynames array start on sunday (søndag)

    2. Weeknumbering:

    First expand the Date-object:
    Date.prototype.getWeek = function() {
    var onejan = new Date(this.getFullYear(),0,1);
    return Math.ceil((((this – onejan) / 86400000) + onejan.getDay()+1)/7);
    }

    and put this in the constructor together with the other settings:

    calendarAfterLoad : function(calendar) {$(“.wc-title:first”).html($(“.wc-title”).html() + ” (Week ” + new Date(calendar.data().endDate).getWeek()+”)”);}

    What it does: Gets the last day of the selected week, gets the weeknumber of the week that date is in, and adds (Week XX) to the calendar title.

    Maybe not very elegantly, but it works…

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s