Calendar Widget Plugin

Inspired by the Dojo calendar, the calendar widget displays events from a data store along time, allowing a user to interactively edit the position in time of these events.

Download the Calendar on GitHub

Source thumb image

View the Sample Application on ariatemplates.com

Sample thumb image

 

Table of contents

1. Loading the calendar
2. Passing data to the calendar
2.1 Bi-directional communication between the calendar and other widgets
3. Configurable properties of the calendar
3.1 Calendar event properties
4. Calendar event handlers
4.1 List of supported event handlers
5. Time zones


 

Loading the calendar

The calendar is a template based widget which can be loaded as a widget library by any template using the following syntax:

{Template {
  $classpath : 'app.SampleTemplate',
  $wlibs : {
    'sample' : 'atplugins.calendarwidget.CalendarWidgetLib',
  },

An instance of the calendar can then be instantiated by the template:

{@sample:Calendar{
    moduleCtrl : {
        classpath : "app.SampleModuleController",
        initArgs : this.data.calendarData
    }
}/}

back to top


 

Passing data to the calendar

When instantiating the calendar, a reference to a module controller together with a data object is passed into the calendar widget. The calendar widget uses bindings on a shared container in its data model to communicate with other widgets that are also bound to the shared container in the data model.

back to top


 

Bi-directional communication between the calendar and other widgets

Lets take a look at the sample to see how this works.  In the sample we have a selection of widgets which form a control panel which is designed to control the calendar widget, note that the control panel is just a sample app and is not actually a part of the calendar widget, however it does demonstrate quite nicely how to achieve bi-directional communication between multiple widgets and the calendar widget.

 

Control Panel

Sample Control Panel

When the control panel UI changes the calendar UI needs to update to reflect that change, similarly when certain parts of the calendar UI change the control panel UI needs to be updated. For this to happen, the widgets in the control panel need to have bindings to objects within the data model that we would like to share with the calendar widget.

Lets focus on one widget from the control panel:

 

Light Calendar

Light Calendar

Firstly, a data object is created when the template is loaded, this data object is called data.calendarData and will be used to share data between the widgets.

    Aria.loadTemplate({
        classpath: "app.SampleTemplate",
        div: "myApp",
        data: {
            calendarData:{}
        }
    });

Within the template scope we now have our container object, which we would like to share between widgets, it can be referenced as this.data.calendarData.

Below is a snippet, taken from the sample, for the light calendar which is synchronized with the calendar widget. Whenever a date is chosen on either the calendar widget or the light calendar, both of the widgets views are updated to reflect the chosen date.

    {@light:Calendar {
        attributes : {
            classList : ["light-calendar"]
        },
        bind : {
            value: {
                to : "date",
                inside : this.data.calendarData
            }
        }
    }/}

You can see that the light calendars value has been bound to date within this.data.calendarData. The calendar widget has an internal binding to its date property, so now it is just a question of linking the two date objects so that when one is updated, so is the other one.

Within your module controller that was passed (by reference) to the calendar widget you can declare property/value pairs which will correspond to the bound properties of the widgets in your template, in the snippet below we will focus on the date property

/**
 * Custom module controller, created by the user and passed into the Calendar widget.
 */

Aria.classDefinition({
    $classpath : "app.SampleModuleController",
    $extends : "widget.controllers.CalendarController",
    $prototype : {
        init : function (data) {
            ...
             this._data = data;
             this.json.inject({
                //calendar properties and values
                date : new Date(),
             }, data);

The data argument within the init method is passed into the module controller, from the template, using initArgs (see Loading the Calendar section above). The bound object for the light calendar is data.date (module controller scope).

There are two parts to consider here within the init method of the module controller, firstly we are creating a link between the data container that is bound to by the light calendar, and the internal data model of the calendar widget

    init : function (data) {
        ...
        this._data = data;

and secondly, we are injecting our default values for both the calendar widget and the light calendar.

this.json.inject({
    date : new Date(),
}, data);

It is this injection, that supplies the calendar widget with its default properties and their values, and subsequently updates the external widgets that form the control panel (through bindings), with their correct values. When the light calendars value is changed, listeners on this._data.date (module controller scope) are notified and the calendar UI is refreshed. Any time the calendar date is changed, listeners on this.data.calendarData.date (template scope) are notified and the light calendar UI is refreshed.

back to top


 

Configurable properties of the calendar

In the same way that we looked at sharing the date property of the calendar widget in the previous section (see Bi-directional communication between the calendar and other widgets) we can also share and configure any of the calendar widget properties using the same technique.

The following properties are available to the calendar widget:

/**
* Can change the starting day for the calendar week view,
* 0 = Saturday through to 6 = Friday
*/

startWeekDay : 0

/**
* Will expand the all day events panel,
* the same as a user clicking on the ▼ icon
*/

allDayExpanded : false

/**
* Contains the default timeZone that will be adopted for the calendar,
* timeZones must be a valid time zone name from the IANA Time Zone Database
* http://en.wikipedia.org/wiki/IANA_time_zone_database#Names_of_time_zones
*/

timeZone : “Europe/London”

/**
* Will make the calendar and any events read-only.  
* It will still be possible to select events thus raising the click events
* for both the calendar events and the calendar,
* however no editing will be possible, this includes resize, drag and drop.  
* It is important to know that visually there is no difference between
* a locked calendar and an unlocked one, only functionally will you be able to tell.
*/

lock : false

/**
* Hour to start the view
* from 0 – 23 (applies to both day and week views).
*/

startDisplayHours : 6

/**
* Minutes to start the view from 0 - 59
* (applies to both day and week views).
*/

startDisplayMinutes: 15

/**
* Sets the minute increments between each calendar hour.
* This property does not visually affect the grid, but the behaviour
* of events, including the drag and drop of event items,
* and the calculation of the event time displayed in the event item title.
*/

interval : 15

/**
* Events array, contains all calendar events
* and their properties.
*/

events: []

back to top

 

Calendar event properties

Stored within the events array, the following event properties are supported:

/**
* Date object containing the date/timestamp for the start of an event
*/

start : Date {Sun Aug 25 2013 00:00:00 GMT+0200 (Romance Standard Time)}

/**
* Date object containing the date/timestamp for the end of an event
*/

end: Date {Sun Aug 25 2013 02:00:00 GMT+0200 (Romance Standard Time)}

/**
* String containing the event title which is displayed in the event
*/

title : “My event”

/**
* Boolean determines if an event is an all day event or not,
* all day events are displayed in a separate panel of the calendar view,
* at the top above the events plotted against time
*/

all_day : true

/**
* Array containing an events time zone information,
* for any new events that a user creates,
* this time zone information is automatically generated
* based on the existing calendar time zone and the selected start and end date/times.
*/

timeZones : [{
              name : "Europe/London",// -/+ 0 hours
              start : Date {Sun Aug 25 2013 00:00:00 GMT+0200 (Romance Standard Time)},
              end : Date {Sun Aug 25 2013 05:00:00 GMT+0200 (Romance Standard Time)}
          }, {
              name : "America/New_York",// -6 hours
              start : Date {Sat Aug 24 2013 18:00:00 GMT+0200 (Romance Standard Time)},
              end : Date {Sun Aug 25 2013 05:00:00 GMT+0200 (Romance Standard Time)}
          }, {
              name : "Europe/Moscow",// +2 hours
              start : Date {Sun Aug 25 2013 02:00:00 GMT+0200 (Romance Standard Time)},
              end : Date {Sun Aug 25 2013 07:00:00 GMT+0200 (Romance Standard Time)}
          }]

/**
* Boolean determines if the event is a holiday event,
* holiday events are displayed in green regardless
* of if they are all day events or not.
*/

holiday : true

/**
* Boolean determines if the event is an immutable object,
* the event will still be selectable,
* the click event will be raised for the event
* and the non all day events colour will still change to blue.
*/

uneditable :  true

back to top


 

Calendar event handlers

Within the calendar widget, there are custom event handlers that are triggered which can be hooked into from your module controller. The custom event handlers are executed whenever certain types of interaction takes place. For instance, if a user clicks on a calendar event item in the sample the itemClick and also the gridClick handlers are called.

In the sample this generates the following log in the console:

Click event handler log

And the source for our handlers, taken from the sample module controller:

    itemClick : function (evt) {    
        var className = "calItem_" + evt.order;                
        this.$logInfo('Calendar event item:"' + className + '" has just been clicked.');                                    
    }

    gridClick : function (evt) {
        this.$logInfo('Calendar grid has just been clicked.');
    }

back to top


 

List of supported event handlers

The following callbacks can be defined in your module controller, they are supported internally by the calendar widget and will be called upon execution of the appropriate user action:

/**
* Triggered when a calendar event item is clicked  
*/

itemClick : function (evt) {}

/**
* Triggered when a calendar event item is double clicked
*/

itemDoubleClick : function (evt) {}

/**
* Triggered when a calendar grid is clicked
*/

gridClick : function (evt) {}

/**
* Triggered when a calendar grid is double clicked
*/

gridDoubleClick : function (evt) {}

/**
* Triggered when a calendar event item is moving
*/

itemEditMove : function (evt) {}

/**
* Triggered when a calendar event item is resizing  
*/

itemEditResize : function (evt) {}

/**
* Triggered when a calendar event item starts being edited  
*/

itemEditBegin : function (evt) {}

/**
* Triggered when a calendar event item finishes being edited
*/

itemEditEnd : function (evt) {}

/**
* Triggered when a calendar event item has been changed  
*/

change : function (evt) {}

/**
* Triggered when a calendar time zone has been changed
*/

timeZoneChange : function () {}

back to top


 

Time zones

The calculated time zones use information from the IANA time zone database. The calendar widget will calculate time zone data for any new event items, based on existing time zone data that is stored in the events array. The time zone information is stored in the timeZones array for each event item.

/**
* Array containing event time zone information,
* for any new events that a user creates,
* this time zone information is automatically generated
* based on the existing calendar time zone and the selected start and end date/times.
*/

timeZones : [{
              name : "Europe/London",// -/+ 0 hours
              start : Date {Sun Aug 25 2013 00:00:00 GMT+0200 (Romance Standard Time)},
              end : Date {Sun Aug 25 2013 05:00:00 GMT+0200 (Romance Standard Time)}
          }, {
              name : "America/New_York",// -6 hours
              start : Date {Sat Aug 24 2013 18:00:00 GMT+0200 (Romance Standard Time)},
              end : Date {Sun Aug 25 2013 05:00:00 GMT+0200 (Romance Standard Time)}
          }, {
              name : "Europe/Moscow",// +2 hours
              start : Date {Sun Aug 25 2013 02:00:00 GMT+0200 (Romance Standard Time)},
              end : Date {Sun Aug 25 2013 07:00:00 GMT+0200 (Romance Standard Time)}
          }]

Whenever a modification to a calendar event item occurs, the calendar widget will first try to extract the correct start/end data based on the previously stored data for that event item for that particular time zone, if none exist, the calendar widget will then create the time zone data it needs and store it in the model so that it can be used next time the calendar event item is modified.

There is also a timeZoneChange event that is raised whenever the calendars timeZone property is updated. This event can be hooked into from your module controller, by defining an event handler for it, and allows a developer to do any post, time zone change, processing.

/**
* Triggered when a calendar time zone has been changed
*/

timeZoneChange : function () {}

back to top

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>