How to set up a Calendar in Drupal Gardens

Check out our new Drupal Gardens Calendar seven-part video tutorial series on how to do this.

At the time of this writing, Drupal Gardens does not offer a native Calendar type of functionality. Since a client really needed it, we decided to roll our own. And since DG has the built-in Date module and does allow for custom javascript, we're in business. The following implementation of Adam Shaw's FullCalendar can be achieved simply by creating a new content type, making a View page, a bit of jQuery and of course CSS. Here are the steps needed:

FullCalendar Ingredients

  1. The FullCalendar jQuery plugin.
  2. Q-Tip jQuery plugin
  3. A custom Calendar Entry content type
  4. A custom View of Calendar Entries
  5. Custom jQuery to wire everything up

Drupal Gardens Calendar - finished product

 

FullCalendar Instructions

  1. Download the latest FullCalendar jQuery plugin. What we're interested in here are two files, fullcalendar.min.js and fullcalendar.css. You want to upload the js to your custom javascript files

    yoursite.com/admin/config/system/javascript-libraries/customand place in the head. Then paste the fullcalendar.css contents in your Advanced CSS section of the Appearance menu. Now create one new custom javascript file with the following contents and place it in the head section. You can call it FullCalendarHead

    jQuery(document).ready(function() {
     
        // initialize the calendar as a blank calendar
        jQuery('#calendar').fullCalendar({
            // put your options and callbacks here
            events: [{}],
            // include the qtip plugin which will show the event description in a popup upon rollover
            eventRender: function(event, element) {
                    element.qtip({
                        content: event.description,
                        position: 'center',
                        hide: {
                            fixed: true, // Make it fixed so it can be hovered over
                            effect: { type: 'fade', length: 430 },
                            delay: 100,
                            },
                        show: {
                            effect: { type: 'fade', length: 430 },
                            delay: 300,
                            },
                        style: {
                            padding: '5px 15px',
                            border: { width: 1, radius: 5 }
                        }
                    });
            }
     
        })
     
    });

    Once Drupal has these three js files, we'll be able to create a fourth js file in the last step which inserts our own events into the calendar by utilizing a Views block.

  2. Create a new content-type called 'Calendar entry' or something to your liking. Then set up a few custom fields in Manage Fields. First create a date field (pop-up widget) as a new field. Make sure to tick the Collect an end date and make this required. Second, create a text field (checkbox widget) to collect whether this event is an all-day event or not. For the values, enter

    false|no
    true|yes

    FullCalendar will not display times for an all-day event. Finally, if you want to colorize the various types of Calendar entries, make a new text field (select list widget) of different types of calendar entries and for the values, list a color in HEX notation followed by a category name for the Calendar type, i.e.

    0052A5|National Holiday

    We can use this later to color-code the entries on the calendar by their category.

    Drupal Gardens Calendar - Calendar entry Content type

  3. Now go ahead and create a couple of Calendar events so we have something to work with.

  4. Date display. Yes indeed you will need some custom date displays set up for this one. Head over to yoursite.com/admin/config/regional/date-time/formats/addand create a new date format with the following string

    D, d M Y H:i:s T

    Then create a new Date type at

    yoursite.com/admin/config/regional/date-time/types/add

    and select your newly created Date format. You can call it 'Full Calendar'. Repeat the same process for the following strings:

    1. M - Call it Month only
    2. Y - Call it Year only
    3. M j - g:ia - Call it Calendar PopUp Display
  5. Create a view with a block. We'll make a view of our Calendar entry content type as an unformatted list. Sort it by the Calendar Date. Make sure to 'Display all items' under Pager. Also create a filter for the calendar with the Start Date field and configure it to your liking. In our case, it was for a school, so we just used '-30 days' and the last day of the school year. Keep in mind that if you have a lot of calendar items, all that markup will appear on the block, so limiting it to some kind of range is best. See how I've done this below.

    Drupal Gardens Calendar - Views date filter

  6. Now we'll include our fields in the view. But before we do, we'll need to place the following code in the Header of your view

    <div id="calendar"></calendar>

    which is where the FullCalendar will be placed. All of your fields will need to be Excluded from display except for the last Global: Custom text field where we'll use the tokens of these hidden fields and supply our own markup. There will need to be 3 of the same Date fields on the view but with different display formatters — one for the start date, one for the end date and one for the display date. The start and end date will use the first custom Date type from above and the display date will use the second Date type you created. You can give all of these fields an Administrative title for clarity under the 'More' tab in the field edit popup. Also include the following fields: Node ID, Title, Body, All Day and Calendar Type (optional). The fields on the view should look like the following:

    Drupal Gardens Calendar - Views

    For the body field, rewrite the output by using the below codeblock (note your token values may differ than mine). Click on style settings and then customize field html and make the body field a div and then provide a class for the body called 'cal-body'.

    <h2>[title_1]</h2>
    <h4>[field_calendar_date]</h4>
    <p>[body]</p>
    <a id="[nid]" class="button" href="/node/[nid]">Read more</a>

    Drupal Gardens Calendar - Views Body markup

    Then for the final field, make a custom text field and rewrite the output using the following codeblock (substituting your token names of course). Also just as with the body field, click on style settings and then customize field html and make the field a div with three classes. Use the replacement tokens for the month only and year only date field values as well as a class called 'cal-item'.

    <span class="cal-start">[field_calendar_date_1]</span>
    <span class="cal-end">[field_calendar_date_2]</span>
    <span class="cal-all_day" name="[field_calendar_all_day]"></span>
    <span  class="cal-type" name="[field_calendar_type]"></span>
    <span class="cal-title">[title]</span> - <span class="cal-body">[body]</span>

    Drupal Gardens Calendar - Views Global markup

  7. Ok at this point we are ready to add a new blank page to our Drupal site and place the view block on it. Go add a basic page and make the title 'Calendar', change the path i.e. to calendar and hit save. Then go visit your blocks

    yoursite.com/admin/structure/blocks

    and put the newly created block from Views into the Content region. Make sure to make the block visibility settings to ONLY show up on the new page path which was created i.e. calendar. For the title of the block, enter

    <none>

    Once you've done that, visit the page and make sure you get a full calendar and a list below that of the view you just created.

  8. At this point you will need to make some style adjustments by clicking on the Appearance menu and then Layout and select a full-page width layout for the current page only. Then go to Advanced menu in the Appearance editor and click on Custom CSS. Copy and paste the contents of the CSS file included with the jQuery plugin, called fullcalendar.css. Click save, then publish and then exit the editor. If you are not seeing the styles, first visit

    yoursite.com/admin/config/development/performance

    and tick off of the js and css compression checkboxes at the bottom, then save and then clear your cache.

  9. The last part of the equation is another custom jQuery bit. Use the following code block to upload one last custom js file and place it in the disabledsection.

    jQuery(document).ready(function($) {
        // show a loading.gif - you'll need css rules for this to work
        jQuery('<div id="throbber"></div>').appendTo(jQuery('.fullcalendar'));
        addEvents();
        jQuery(".fc-button-prev, .fc-button-next").bind('click', function(){
            addEvents();
        });
    });
     
    function addEvents() {
      // wait 2 seconds to give time for the calendar to render first
      setTimeout(function(){
        // get the month and year of the current calendar like December.2012
        calMonth = jQuery('.fc-header-title').text();
        calMonth = calMonth.replace(' ', '.');
        // loop through and add events from the view - note the class of your view may differ, mine is named 'fullcalendar'
        jQuery(".view-id-fullcalendar").find("div.cal-item."+calMonth+":not(.processed)").each(function(index, value) {
          event=new Object();
          event.id=jQuery(this).find('span.cal-body a').attr('id');
     
          // get our start and end dates the way FullCalendar wants them
          var start=jQuery(this).find('span.cal-start span.date-display-single').text();
          var myStart = new Date(start);
          event.start = myStart.getTime()/1000.0;
     
          var end=jQuery(this).find('span.cal-end span.date-display-single').text();
          var myEnd = new Date(end);
          event.end = myEnd.getTime()/1000.0;
     
          // get all of our fields
          event.title=jQuery(this).find('span.cal-title').text();
          event.description=jQuery(this).find('span.cal-body').html();
          allday = jQuery(this).find('span.cal-all_day').attr('name');
          event.color = "#"+jQuery(this).find('span.cal-type').attr('name');
          event.allday = String(allday);
     
          // if it's an all day event, we need to alter the description and only send the start date
          if (event.allday == 'true') {
              datefield = jQuery(this).find('span.cal-body h4 span.date-display-single');
              datehtml = datefield.html();
              var dateparts = datehtml.split(" - ");
              datereplace =  dateparts[0];
              event.description = event.description.replace(datehtml, datereplace);
              jQuery("#calendar").fullCalendar('renderEvent',
                {
                  title : event.title,
                  start : event.start,
                  description : event.description,
                  color: event.color,
                  allDay: true,
                  className: event.id,
                }, true);
          }
          else {
              jQuery("#calendar").fullCalendar('renderEvent',
                {
                  title : event.title,
                  start : event.start,
                  end : event.end,
                  description : event.description,
                  color: event.color,
                  allDay: false,
                  className: event.id,
                }, true);
          }
     
          jQuery(this).addClass('processed');
          jQuery('#throbber').remove();
        });
      }, 2000);
    }
  10. Now finally go back to the block admin page and edit the block settings for your Views block. At the bottom of the block settings click on JavaScript libraries and choose the js file you just uploaded and then revisit your calendar page. Be sure to turn off css/js compression and clear your cache if you are having difficulty.

Gotchas and Troubleshooting

The main issue during this development was the caching of javascript custom uploads. If you make changes to any custom javascript file and want to Edit the file or remove it and upload a new version for testing, be sure to click on the filename after uploading to see if your changes 'stick'. I found the only way to make sure my new file was going to overwrite the old one, was to rename it before uploading it.

Again clear your cache. You also should test in the same browser you are developing on as DG cache's pages for anonymous users and it's not reliable to immediately test a new change in another browser.

If things are not working for you, the first thing to do is make sure your fields are set up correctly with the same names as mine as well as the Views tokens are done correctly. In other words, this tutorial is built on a specific naming convention for CCK fields, Views fields and javascript fields. If you go through the code snippets here from each of those three, the field names should all match up.

Conculsion

So that's it for a quick and dirty Calendar implementation for Drupal Gardens. Happy gardening and stay tuned for more tutorials like this one to come.

Comments

I've gone throught the videos twice, gone back through the blog, followed the troubleshooting above and the events still wont show up on the calendar. I wonder what step I'm missing?

Thanks for your great tutorial. I did every steps just like you however, I am not able to get the events inside the calendar. I think the JQuery from step 9 does not work for me. Is there any way to debug execution of this script ? Any recommendation is highly appreciated. 

dripal's picture

Look at this line in Step 9. You need to make sure the jQuery selector is selecting your view which may have a different class // loop through and add events from the view - note the class of your view may differ, mine is named 'fullcalendar' jQuery(".view-id-fullcalendar").find("div.cal-item."+calMonth+":not(.processed)").each(function(index, value) { Also any time you re-upload the step 9 js file (NOTE: to the disabled region), you have to do step 10 and re-attach the view to the block. Hope that helps. If not, send me a link via my contact form and I'll take a look at the page.

Add new comment