Calendar with highlighted dates

In Drupal 7, it’s easy to show calendar (ui.datepicker) date selector to user. (it’s not hard in Drupal 6, too - but in d6 you need to enable http://drupal.org/project/jquery_ui to get the calendar, I think)

You just write several lines of js code, and you get a calendar.
But things are quickly getting more complicated when you need to allow visitors to choose from dates that have some nodes “attached” to them only. E.g. if you have news view, and you don’t have news for 13 Nov 2011, there is no sense in allowing user to click on this date in calendar (I’m talking about the case when clicking on calendar redirects user to views page /news/2011/11/02 , where 2011/11/02 is a context filter for news nodes)

Here is the screenshot illustrating the desired functionality:

Calendar with available dates

(so, user can click on Nov 3 - but not on Nov 4)

I’m not sure if there is a module to do the stuff I’ve described in this post, but I couldn’t find one, and since I was asked 3 times to implement such date-restricting feature - I hope it can be useful for someone.

Okay, so the overall idea is:

1. Use jquery.ui.datepicker to show calendar to user
2. Use several lines of js code to hook into calendar days rendering, and allow/disallow date selection if the date has/doesn’t have available nodes.
3. Implement corresponding PHP method to query database and prepare data for code in step#2.

And here is the code (I recommend to put it to /your_module/js/cal_improve.js):

(function ($) {

Drupal.behaviors.cal_restrict_selection = {
  attach: function(context) {
    if (!$('body', context)) return; // don't run the processing if it's an ajax call
   
    // in my case, I was using calendar on textfield of views exposed filter of type 'date'
    // disable date selection while we use ajax to load available dates
    $('#views-exposed-form-events-page #edit-start-value-datepicker-popup-1').attr('disabled', true);
   
   // just call  mywebsite.com/dateload_events which returns JSON array of available dates (see php code of this page below)
   // and enable calendar for textfield afterwards
    $.getJSON(Drupal.settings.basePath + 'dateload_events', {}, function(data, textStatus, jqXHR) {
          _event_days = data;
           $('#views-exposed-form-events-page #edit-start-value-datepicker-popup-1').attr('disabled', false);
        });
       
    $('#views-exposed-form-events-page #edit-start-value-datepicker-popup-1').datepicker({    
      dateFormat: 'yy-mm-dd',
      firstDay: 1, // first day is Monday

     
      beforeShowDay: function(date) {
        var day = date.getFullYear() + '-' + (date.getMonth()+1) + '-' + date.getDate();
        if (_event_days[day]) {
          return [true];
        } else {
          return [false];
        }
      }
    });
   
  }
}
})(jQuery);

PHP code for /dateload_events callback (defined in yourmodule/yourmodule.module):

<?php
function yourmodule_init() {
 
$path = drupal_get_path('module', 'yourmodule'); 
 
 
// I need the calendar only on /news/* pages
 
if(arg(0) == 'news') {   
   
// load ui.datepicker from core
   
drupal_add_library('system', 'ui.datepicker');
   
// and our js
   
drupal_add_js($path . '/js/cal_improve.js');
  }

}


function
yourmodule_menu() {
 
$items = array();
 
$items['dateload_events'] = array(
   
'title' => 'Date load',
   
'type' => MENU_CALLBACK,
   
'page callback' => 'yourmodule_event_dates',
   
'access arguments' => array('access content'),
  );
  return
$items;




function
yourmodule_event_dates() {
 
// retrieve list of dates in %Y-%c-%e format where at least 1 published node
  // of type 'event' exists. I use fetchAllKeyed(0,0) method that returns array
  // where key=value, so the returned array looks like:
  //   array(
  //     '2011-11-1' => '2011-11-1',
  //     '2011-11-3' => '2011-11-3'
  //   );
  //
  // it's easy to modify the code to return number of items for specific day
  // but I didn't need that in my project.
  // 'field_date_interval' is the name of my date field attached to node type
  // 'event'.
 
 
$dates = db_query("SELECT DATE_FORMAT(date.field_date_interval_value, '%Y-%c-%e') as day
  FROM {node} n INNER JOIN {field_data_field_date_interval} date
  ON n.vid=date.revision_id
  WHERE n.type=:ctype AND n.status=1 GROUP BY day
  ORDER BY date.field_date_interval_value "
, array(':ctype' => 'event'))->fetchAllKeyed(0,0);
 
 
// renders php array as json
 
drupal_json_output($dates);
}
?>

Important notes:

- I use beforeShowDay() event of ui.datepicker to modify day interaction.
here is the event description from jquery.ui website:

The function takes a date as a parameter and must return an array with [0] equal to true/false indicating whether or not this date is selectable, [1] equal to a CSS class name(s) or ” for the default presentation, and [2] an optional popup tooltip for this date. It is called for each day in the datepicker before it is displayed.

Code examples

Supply a callback function to handle the beforeShowDay event as an init option.
$(‘.selector’).datepicker({
beforeShowDay: function(date) { … }
 });

there are other useful methods of ui.datepicker, you can find them here:
http://jqueryui.com/demos/datepicker/

- In Javascript, the date.getMonth() function returns month numbers starting from 0! (in PHP, it starts from 1)

You can see working example of the calendar here (“Дата” field in left sidebar)

Comments

Shouldn't the cck field should be date field ?

14 November, 2011

Yes, it should be a date field.

14 November, 2011

Hello,
I would like to insert a field in datepicker content type, but with an additional option for this field would require me to enter a value for each date for my admin section and in the front office I have a table with my dates a week and each time I see under the number I have entered in the admin.
In advance thank you for your response.
cordially

28 May, 2012

Great! Thank you!

20 September, 2012

Works perfectly... except for Google Chrome... Some Javascript strangeness make that it doesn't always work... :(

27 September, 2012

Hi Anton,

Thanks for your contribution.

I was looking for this functionality and I found your blog.

I tried your code but unfortunately I am not able to make it work for me. Can you kindly help me getting this to work? It would be very helpful. We need this functionality.

Thanks & Regards,
Saurabh Agrawal

10 November, 2012

Hi,

I tried your module in Drupal 7. Also is it possible to use this in Drupal 6?

Thanks & Regards,
Saurabh Agrawal

10 November, 2012

Any Idea if there is a Module that Allows this now? I've been searching everywhere for something like this.

30 May, 2013

Calendar module + Date module + Views does very similar thing in Drupal 7 (there is a views block for month view).

18 June, 2013

Post new comment

Private and will not be shown publicly.
  • Web page addresses and e-mail addresses turn into links automatically.
  • Allowed HTML tags: <a> <em> <strong> <cite> <code> <ul> <ol> <li> <dl> <dt> <dd>
  • Lines and paragraphs break automatically.

More information about formatting options

Note for potential spammers: all links in your comment will not be indexed by search engines.

Anton Sidashin

Anton Sidashin senior developer, Pixeljets co-founder

I'm a web developer specializing in PHP and Javascript, and Drupal, of course. I'm building Drupal projects since 2005, and I was working as full-time senior engineer in CS-Cart for a while, building revolutionary e-commerce software. In my free time, I enjoy playing soccer, building my body in gym, and playing guitar.

Drupal.org ID: restyler
Drupal association member