Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Styling first and last days of CLNDR.js calendar multi-day events

I am using clndr.js (http://kylestetz.github.io/CLNDR/) to display dates that a holiday cottage is booked for. These are always shown using the multi-day event system as the minimum booking is 3 days. I now need to style the first and last days of the event differently, to show they are changeover days. Ideally I would do this by adding a class to the td. This is what I have so far:

JS

$('#calendar').clndr({
          template: $('#calendar-template').html(),
          weekOffset: 1,
           daysOfTheWeek: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'],
           targets: {
               nextButton: 'clndr-next',
               previousButton: 'clndr-previous'
           },
           multiDayEvents: {
               startDate: 'start',
               endDate: 'end'
           },
           events: events,
           clickEvents: {
               click: function(target) {
                   //alert(target);
               }
           }
      });

Example JSON

var events = [
  {start:'2016-05-29T00:00:00+00:00',
  end:'2016-06-01T00:00:00+00:00',
  title:'Mrs A N Human',},
  {start:'2016-08-10T00:00:00+00:00',
  end:'2016-08-17T00:00:00+00:00',
  title:'Mr A Person',}
];

HTML / Underscore

 <div id="calendar">
  <script type="text/template" id="calendar-template">
   <table class="table">
    <thead>
     <tr>
      <th class='clndr-previous'>&lt;</th>
      <th colspan="5"><%= month %> <%= year %></th>
      <th class='clndr-next'>&gt;</th>
     </tr>
     <tr>
      <% _.each(daysOfTheWeek, function(day) { %>
      <th class="header-day"><%= day %></th>
      <% }); %>
     </tr>
    </thead>
    <tbody>
      <tr class="days"><% _.each(days, function(day, index) { %>
      <td class="<%= day.classes %>" id="<%= day.id %>">
       <span class="day-number">
       <%= day.day %>
       </span>
     </td>
      <% if ((index + 1) % 7 == 0) { 
           %> </tr><tr> <% 
           } %><% }); %>
     </tr>
    </tbody>
   </table>
  </script>
</div>

I am struggling to work out how to target those first and last days to apply some different styling. I am using moment.js as well if that can be used. Help greatly appreciated!

like image 386
Mike Harrison Avatar asked Jun 17 '16 09:06

Mike Harrison


2 Answers

So eventually I spent some time looking at using Underscore and Moment to achieve what I was after. Below is my updated code, using a conditional in Underscore to check the date using Moment, and add a class to the <td> if necessary. This was combined with an adjustment to how my events were represented in the JSON array:

HTML / Underscore

<div id="calendar">
  <script type="text/template" id="calendar-template">
    <table class="table">
      <thead>
        <tr>
          <th class='clndr-previous'>&lt;</th>
          <th colspan="5"><%= month %> <%= year %></th>
          <th class='clndr-next'>&gt;</th>
        </tr>
        <tr>
          <% _.each(daysOfTheWeek, function(day) { %>
          <th class="header-day"><%= day %></th>
          <% }); %>
        </tr>
      </thead>
      <tbody>
        <tr class="days">
          <% _.each(days, function(day, index) { %>
            <td class="<%= day.classes %> <% _.each(day.events, function(event) { %><% if( moment(event.start).isSame( day.date ) ){ %>start<% } %><% }); %> <% _.each(day.events, function(event) { %><% if( moment(event.end).isSame( day.date ) ){ %>end<% } %><% }); %>">
              <span class="day-number"><%= day.day %></span>
            </td>
          <% if ((index + 1) % 7 == 0) { %> </tr><tr>  <% } %>
          <% }); %>
         </tr>
       </tbody>
    </table>
  </script>
</div>

JSON

var events = [
  {start:'2016-05-29',
  end:'2016-06-01',
  title:'Mrs A N Human',},
  {start:'2016-08-10',
  end:'2016-08-17',
  title:'Mr A Person',}
];
like image 122
Mike Harrison Avatar answered Nov 09 '22 13:11

Mike Harrison


Okay so I hope you can find some of this useful as it took me a long time to get this to work. You will probably need to modify some bits for your template etc. but should give you a good idea. Pay attention to the <% _.each part as that's what makes the class work from the multi event JSON

Here's my CLNDR template code:

<div id="mini-clndr">
  <script id="mini-clndr-template" type="text/template">
    <div class="controls">
      <div class="clndr-previous-button"><img src="/assets/local/img/calendar-left-arrow.png"></div>
      <div class="month">
        <%= month %>
          <%= year %>
      </div>
      <div class="clndr-next-button"><img src="/assets/local/img/calendar-right-arrow.png"></div>
    </div>

    <div class="days-container">
      <div class="days">
        <div class="headers">
          <% _.each(daysOfTheWeek, function(day) { %>
            <div class="day-header">
              <%= day %>
            </div>
            <% }); %>
        </div>
        <% _.each(days, function(day) {
                    var classes = '';
                    if( day.events.length ){
                        for( var i = 0; i < day.events.length; i++ ){
                            classes += ' ' + day.events[i].class;
                        }
                    }
                %>
          <div class="<%= day.classes %><%= classes %>" id="<%= day.id %>">
            <%= day.day %>
          </div>
          <% }); %>
      </div>
      <div class="events">
        <div class="headers">
          <div class="x-button">x</div>
          <div class="event-header">EVENTS</div>
        </div>
        <div class="events-list">
          <% _.each(eventsThisMonth, function(event) { %>
            <div class="event">
              <a target="blank" href="<%= event.url %>">
                <%= moment(event.date).format('MMMM Do') %>:
                  <%= event.title %>
              </a>
            </div>
            <% }); %>
        </div>
      </div>
    </div>
  </script>
</div>

Here's my CLNDR.js code:

  var clndr = {};

  $(function() {

    var currentMonth = moment().format('YYYY-MM');
    var nextMonth = moment().add(1, 'month').format('YYYY-MM');

    var events = [
      // Multiday Event Code
      {
        start: '2016-05-17',
        end: '2016-05-19',
        title: 'Monday to Friday Event',
        class: 'long-event'
      },
    ];

    $('#mini-clndr').clndr({
      template: $('#mini-clndr-template').html(),
      weekOffset: 1,
      events: events,
      multiDayEvents: {
        endDate: 'end',
        singleDay: 'date',
        startDate: 'start'
      },
      clickEvents: {
        click: function(target) {
          if (target.events.length) {
            var daysContainer = $('#mini-clndr').find('.days-container');
            daysContainer.toggleClass('show-events', true);
            $('#mini-clndr').find('.x-button').click(function() {
              daysContainer.toggleClass('show-events', false);
            });
          }
        }
      },
      adjacentDaysChangeMonth: true,
      forceSixRows: false,
      showAdjacentMonths: false,
    });
  });

Then my CSS code:

  .long-event {
    background: orange;
  }

  :not(.long-event) + .long-event, .long-event:first-child {
    background: orange;
    border-radius: 50% 0 0 50%;
  }

  .last {
    border-radius: 0 50% 50% 0;
  }

And then finally, some jQuery to make those classes work. You'll also need to add a .date class to every date on the calendar:

$('.long-event + .date:not(.long-event)').prev().addClass('last');

Although this jsFiddle isn't using CLNDR.js, you can see the styling working :)

https://jsfiddle.net/andyjh07/ke0euh5m/

like image 27
Andy Holmes Avatar answered Nov 09 '22 13:11

Andy Holmes