Create astonishing iCal-like calendars with jQuery

According to my web designer experience, one of the most common requests from clients when it comes to WordPress personalization, is to add a basic event calendar to their website.

Finding a good place to position a big table like a calendar within your WordPress template is always a taught work. In addition, the <table> tag itself is often quite difficult to style in a good way.

One of the calendar solution that I came out with and that I’m particulary proud of is the one I built inside the freshly launched Graham Watson for President website.

View the online Demo!

I wanted it to be similar to the iPhone Calendar application (or, if you want, to the little calendar on the left bottom corner in iCal). And I also wanted to keep the code as little and sweet as possible (we don’t_undefined like maintenance, do we?).

Here’s_undefined the simple HTML code I used, the simplest you could ever come up with:

index.html
1 
2 
3 
4 <table cellspacing=
"0"> 
5 <thead> 
6 <tr> 
7 <th>Mon</th><th>Tue</th><th>Wed</th> 
8 <th>Thu</th><th>Fri</th><th>Sat</th>
 9 <th>Sun</th> 10 </tr> 11 </thead> 12 <tbody> 13 
<tr> 14 <td class="padding" colspan="3"></td> 15 <td> 1</td> 16 <td> 2</td> 17 <td> 3</td> 
18 <td> 4</td> 
19 </tr> 
20 <tr> 
21 <td> 5</td> 
22 <td> 6</td> 23 <td> 7</td> 
24 <td> 8</td> 
25 <td class="today"> 9</td> 
26 <td>10</td> 
27 <td>11</td> 
28 </tr> 
29 <tr> 
30 <td>12</td> 31 <td class="date_has_event"> 32 13 33 </td> 
34 <td>14</td> 
35 <td>15</td> 
36 <td>16</td> 
37 <td>17</td> 
38 <td>18</td> 
39 </tr> 
40 <tr> 
41 <td>19</td> 
42 <td>20</td> 
43 <td>21</td> 
44 <td class="date_has_event"> 
45 22 
46 </td> 
47 <td>23</td> 
48 <td>24</td> 49 <td>25</td> 
50 </tr> 
51 <tr> 
52 <td>26</td> 
53 <td>27</td> 
54 <td>28</td> 55 <td>29</td> 
56 <td>30</td> 
57 <td>31</td> 
58 <td class="padding"></td> 
59 </tr> 
60 </tbody> 
61 <tfoot> 
62 <th>Mon</th><th>Tue</th><th>Wed</th> 
63 <th>Thu</th><th>Fri</th><th>Sat</th> 
64 <th>Sun</th> 
65 </tfoot> 
66 </table>

All the magic takes place with some ninja CSS:

 

style.css
1
2
3 table {
4 border-collapse: separate;
5 border: 1px solid #9DABCE;
6 border-width: 0px 0px 1px 1px;
7 margin: 10px auto;
8 font-size: 20px;
9 }
10 td, th {
11 width: 81px;
12 height: 81px;
13 text-align: center;
14 vertical-align: middle;
15 background: url(../img/cells.png);
16 color: #444;
17 position: relative;
18 }
19 th {
20 height: 30px;
21 font-weight: bold;
22 font-size: 14px;
23 }
24 td:hover, th:hover {
25 background-position: 0px -81px;
26 color: #222;
27 }
28 td.date_has_event {
29 background-position: 162px 0px;
30 color: white;
31 }
32 td.date_has_event:hover {
33 background-position: 162px -81px;
34 }
35 td.padding {
36 background: url(../img/calpad.jpg);
37 }
38 td.today {
39 background-position: 81px 0px;
40 color: white;
41 }
42 td.today:hover {
43 background-position: 81px -81px;
44 }

Please note a couple of things here, as it’s_undefined the trickiest part:

  • Make your images seamless. Draw only the top and right border of the cells inside the image: neighbour cells will continue the pattern. Then add the bottom and left border to the table via CSS to complete the work.
  • Use a single image for all the graphics whenever is possible to decrease the download speed time (just a single TCP three-way-handshake to manage, a single Apache request to be answered by your server, a single PNG header overhead to be downloaded).

In addition to the plain calendar structure, we obviously also want the events description to show up on mouse hover. To do that, just add this block inside the calendar cells:

index.html
1 <td class=“date_has_event”>
2 13
3 <div class=“events”>
4 <ul>
5 <li>
6 <span class=“title”>Event 1</span>
7 <span class=“desc”>Lorem ipsum dolor sit amet, consectetu adipisicing elit.</span>
8 </li>
9 <li>
10 <span class=“title”>Event 2</span>
11 <span class=“desc”>Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</span>
12 </li>
13 </ul>
14 </div>
15 </

And use the beautiful, handy, lightweight Coda-like effect for jQuery to bring it to life (how I love jQuery?)

index.html
1 
2 
3 $(function () { 
4 $('.date_has_event').each(function () { 
5 // options 
6 var distance = 10; 
7 var time = 250; 
8 var hideDelay = 500; 
9 
10 var hideDelayTimer = null; 
11 
12 // tracker 
13 var beingShown = false; 
14 var shown = false; 
15 
16 var trigger = $(this); 
17 var popup = $('.events ul', this).css('opacity', 0); 
18 
19 // set the mouseover and mouseout on both element 
20 $([trigger.get(0), popup.get(0)]).mouseover(function () { 
21 // stops the hide event if we move from the trigger to the popup element 
22 if (hideDelayTimer) clearTimeout(hideDelayTimer); 
23 
24 // don't trigger the animation again if we're being shown, or already visible 
25 if (beingShown || shown) { 
26 return; 
27 } else { 
28 beingShown = true; 
29 
30 // reset position of popup box 
31 popup.css({ 
32 bottom: 20, 
33 left: -76, 
34 display: 'block' // brings the popup back in to view 
35 }) 
36 
37 // (we're using chaining on the popup) now animate it's opacity and position 
38 .animate({ 
39 bottom: '+=' + distance + 'px', 
40 opacity: 1
 41 }, time, 'swing', function() { 
42 // once the animation is complete, set the tracker variables 
43 beingShown = false; 
44 shown = true; 
45 }); 
46 } 
47 }).mouseout(function () { 
48 // reset the timer if we get fired again - avoids double animations 
49 if (hideDelayTimer) clearTimeout(hideDelayTimer); 
50 
51 // store the timer so that it can be cleared in the mouseover if required 
52 hideDelayTimer = setTimeout(function () { 
53 hideDelayTimer = null; 
54 popup.animate({ 
55 bottom: '-=' + distance + 'px', 
56 opacity: 0 
57 }, time, 'swing', function () { 
58 // once the animate is complete, set the tracker variables 
59 shown = false; 
60 // hide the popup entirely after the effect (opacity alone doesn't do the job)
 61 popup.css('display', 'none'); 
62 }); 
63 }, hideDelay); 
64 }); 
65 }); 
66 });

This is the CSS code used to style the popup div:

style.css
1 
2 
3 .events { 
4 position: relative; 
5 } 
6 .events ul { 
7 text-align: left; 
8 position: absolute; 
9 display: none; 
10 z-index: 1000; 
11 padding: 15px; 
12 background: #E7ECF2 url(../img/popup.png) no-repeat; 
13 color: white; 
14 border: 1px solid white; 15 font-size: 
15px; 
16 width: 200px; 
17 -moz-border-radius: 3px; 
18 -khtml-border-radius: 3px; 
19 -webkit-border-radius: 3px; 
20 -border-radius: 3px; 
21 list-style: none; 
22 color: #444444; 
23 -webkit-box-shadow: 0px 8px 8px #333; 
24 } 
25 .events li { 
26 padding-bottom: 5px; 
27 } 
28 .events li span { 
29 display: block; 
30 font-size: 12px; 
31 text-align: justify; 
32 color: #555; 
33 } 
34 .events li span.title { 
35 font-weight: bold; 
36 color: #222; 37 }

Please note how nice the box-shadow CSS property is when applied to the popup… unfortunately, this CSS3 property is still only implemented in WebKit browsers (Safari, Google Chrome), but more of them are about to support it.

Download the source files!

And… that’s_undefined it. Simple and sweet, as we wanted. Obviously, you’ll_undefined have to properly configure your preferred WordPress plugin to output a code like the one I showed you, but that’s_undefined the boring part of the lesson and I’ll_undefined skip it 🙂 Instead, let me just add a note…

Choosing the right WordPress Plugin

There are plenty of pretty good WordPress calendar plugins around to facilitate your backend work. I can tell you I tried them all, and the one that convinced me the most was Event Calendar.

With Event Calendar you can add a countless number of events to any post or page directly within the New and Edit page, there’s_undefined a lot of great functions you can use to freely tweak the event-browsing experience within your PHP template — but some work still should be done in this direction — it’s_undefined AJAX ready and the plugin itself is already localized in 19 languages.

Hope you’ve_undefined enjoyed the tut! I’ll_undefined try to reply to your question in my free time :