On the Grafish Design’s Blog I noticed The Small Calendar. That is a small calendar that lets you check your chosen dates for the day of the week. Calendar posted there is a printing version (available for download in 30 languages). This calendar is different from the standard that has only one block from the days of the month. I decided to create a small calendar on-line using PHP a little of jQuery, plus of course CSS.
Target
The calendar in original version looks like this:
source: Grafish Design’s Blog – The small calendar 2010 (en) 1 .
Scheduled my version will have:
- Looks like the original
- Choicing year, other than present
- Multilingualism
- The possibility of highlighting column of dates
- The possibility of highlighting rows months
- The possibility of highlighting days of the week selected dates
- The possibility of moving dates block after clickin on the row of the month
Generating the calendar: PHP
To generate the calendar we will use a simple class which will generate us a few things. First, we create a list of months, for each of them we will check the number of days, check for the first day of the week of the month. Then on this basis, we will create an array that will contain the abbreviations of months (in the chosen language), for a selected year, for each attribute the number of days months and adequately sorted abbreviations days of the week.
The class is very simple, we can even call it imitation of a class or set of functions packed into a class.
Methods list:
- public __construct – 2 optional arguments: year, array with the language translation | constructor
- public setLanguage – 1 argument: array with the translation | setting the language
- public getdatesTable – 0 arguments | makes days array
- public getCalendar – 0 arguments | gets the array with the calendar
- private generateMonths – 0 arguments | makes months array
- private generateDayNames – 0 arguments | makes days of week in correct order
Code of the calss
The server-side part is so simple that it requires no description. Constructor can take 2 parameters: a year and a array with a translation. Both parameters are optional, the default is the current year and the Polish language.
SetLanguage method sets the language. Another, getDatesTable generates an array of day months (1-31), denoting respectively the number of days by months. getCalendar inovokes two other methods: generateMonths – generates an array of months, along with important data, and generateDayNames – abridgment for days of week names.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 | <?php /** * VokielSmallCalendar class * @author Vokiel | http://blog.vokiel.com */ class VokielSmallCalendar { /** * Selected year * @var int $year */ private $year; /** * Shortcuts names for months * @var array $monthsShort */ private $monthsShort = array(); /** * Shortcuts names for week days * @var array $daysShort */ private $daysShort = array(); /** * Generated months table for the calendar * @var array $months */ private $months = array(); /** * Construct, * @param int $year * @param array $lang */ public function __construct($year=0,$lang=null){ $this->year = ($year)? (int)$year : date('Y'); if (!is_array($lang) || !is_array($lang['months']) || !is_array($lang['days'])){ $lang = null; } $this->setLanguage($lang); }//end of __construct /** * Setting the monts shortcuts names and days shorcuts names. * Polish is default language. * @param array $lang Monts and days array starting from 1 = January and 1 = Monday */ public function setLanguage($lang=null){ $this->monthsShort = (is_array($lang['months']))? $lang['months'] : array(1=>'Sty',2=>'Lut',3=>'Mar',4=>'Kwi',5=>'Maj',6=>'Cze',7=>'Lip',8=>'Sie',9=>'Wrz',10=>'Paź',11=>'Lis',12=>'Gru'); $this->daysShort = (is_array($lang['days']))? $lang['days'] : array(1=>'Pon',2=>'Wt',3=>'Śr',4=>'Czw',5=>'Pt',6=>'Sob',7=>'Nie'); }//end of setLanguage method /** * Generating the dates table (numbers from 1 to 31) * @return string $datesTable Generated HTML table */ public function getDatesTable(){ $datesTable = '<table><tbody><tr>'; for ($i=1;$i<32;$i++){ $class = ''; if ($i>=28){ if ($i == $this->months[2]['daysCount'] || $i>29){ $class = 'class="days_'.$i.'"'; } } $datesTable .= '<td '.$class.'>'.$i.'</td>'; if ($i%7==0){ $datesTable .= '</tr><tr>'; } } $datesTable .= '</tr></tbody></table>'; return $datesTable; }//end of getdatesTable method /** * Getting the calendar * @return array $this->months Array with months shortcuts names and sorted week days shortcuts names */ public function getCalendar(){ $this->generateMonths(); $this->generateDayNames(); return $this->months; }//end of getCalendar method /** * Generating months table */ private function generateMonths(){ for ($i=1;$i<13;$i++){ $time = mktime(0,0,0,$i,1,$this->year); $this->months[$i]['weekDay'] = date('N',$time); $this->months[$i]['montShort'] = $this->monthsShort[$i]; $this->months[$i]['daysCount'] = date('t',$time); } }//end of generateMonths method /** * Generating week day names shortcuts */ private function generateDayNames(){ foreach ($this->months as $month => $dayStart){ $dayStart = $dayStart['weekDay']; for ($i=0;$i<7;$i++){ $day = ($dayStart+$i>7)? (-(7-$dayStart-$i)) : ($dayStart+$i); $this->months[$month]['weekdays'][] = $this->daysShort[$day]; unset($this->months[$month]['weekDay']); } } }//end of generateDayNames method }// end of VokielSmallCalendar class ?> |
Handling of the calendar: JavaScript
In this section we will do some javascripting work (using jQuery) with the calendar in order to give it functionality, dynamism and usability. According to our assumptions we need to create some functions that will respond to moving mouse over the calendar fields.
JavaScript code
First function is to highlight the columns of the tables in response to the mouseover of the months. Next part of this function removes hilight after the pointer leaves an element. This is some kind of rollover.
Next section is responsible for the animation after clicking on the month. Block with a list of the days chanes position, moving just under a month selected (clicked).
SendYear function is to indicate the PHP script the user chosen year. Next actions are already rather cosmetic: accepting only the integers in the field of the year, automatically sending the form by pressing enter, clear the box by pressing the Esc key.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 | $(document).ready(function(){ /** * Actions after moving cursor over chosen month * Hilights column in dates table and chosen month */ $('li:not(.daysTable) span').mouseenter(function(){ var $this = $(this); var spanNr = $this.parent('li').children('span').index($this); /* nr dnia tygodnia (od zera) */ $this.parent('li').addClass('hover'); var tab = $this.closest('ul').find('li.daysTable table tr'); tab.each(function(){ $(this).find('td:eq('+spanNr+')').addClass('hover'); }); }).mouseleave(function(){ var $this = $(this); var spanNr = $this.parent('li').children('span').index($this); /* nr dnia tygodnia (od zera) */ $this.parent('li').removeClass('hover'); var tab = $this.closest('ul').find('li.daysTable table tr'); tab.each(function(){ $(this).find('td:eq('+spanNr+')').removeClass('hover'); }); }); /** * Clicking on chosen month * Moves table with dates just after the clicked month */ $('li:not(.datesTable)').click(function(e){ e.preventDefault(); var $this = $(this); var dt = $this.parent('ul').children('li.datesTable'); dt.slideUp(1000,function(){ $this.after(dt); }).delay(50).slideDown('normal'); }); /** * Action after moving cursor over chosen day in the table of days (1-31) * Hilights days over all months */ $('li.datesTable table tr td').mouseenter(function(){ var $this = $(this); var tdNr = $this.parent('tr').children('td').index($this); /* nr dnia miesiaca (od zera) */ var sp = $this.closest('ul').children('li:not(.datesTable)'); sp.each(function(){ $(this).find('span:eq('+tdNr+')').addClass('hover'); }); var tab = $this.closest('table tbody').children('tr'); tab.each(function(){ $(this).find('td:eq('+tdNr+')').addClass('hover'); }); }).mouseleave(function(){ var $this = $(this); var tdNr = $this.parent('tr').children('td').index($this); /* nr dnia miesiaca (od zera) */ var sp = $this.closest('ul').children('li:not(.s)'); sp.each(function(){ $(this).find('span:eq('+tdNr+')').removeClass('hover'); }); var tab = $this.closest('table tbody').children('tr'); tab.each(function(){ $(this).find('td:eq('+tdNr+')').removeClass('hover'); }); }); /** * Function for sending new typed year */ function sendYear(){ var y = parseInt($('#year').val()); if (y>1901 && y<2038){ location.href = '?year='+y; }else{ $('#year').addClass('error'); } } /** * Accept button clicked - sending new date */ $('#accept').click(function(e){ e.preventDefault(); sendYear(); }); /** * Accept only numbers */ $('#year').keyup(function(e){ $(this).val($(this).val().replace(/\D/g,'')); }); /** * Checking key code on year field (esc, enter keys only) */ $('#year').keydown(function(e){ if (e.keyCode==13){ /* enter - send new year */ sendYear(); }else if (e.keyCode==27){ /* esc - clear form */ $(this).val(""); } }); /** * Remove 'error' clas after focusing year field */ $('#year').focus(function(){ $(this).removeClass('error'); }); /** * Changing language */ $('#lang').change(function(){ var url = new String(document.location); url.toLowerCase(); if (url.indexOf('year') > -1) { if (url.indexOf('lang') > -1){ url = url.replace(/lang(.*)/gi,''); } document.location = url + '&lang=' + $(this).find(':selected').val(); }else{ document.location = '?lang=' + $(this).find(':selected').val(); } }); }); |
CSS styling
CSS styles do not require extensive discussion. It is important to highlight only a few tags that make it possible to match the appearance of a specific timetable for their needs. Colors for the rows of months, in which the number of days equal to 30, 31 and 28 or 29 are marked with those classes:
.days_31, .days_30, .days_29 or .days_28
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 | /* reset css */ @CHARSET "UTF-8"; html, body, div, span, applet, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, pre, a, abbr, acronym, address, big, cite, code, del, dfn, em, font, img, ins, kbd, q, s, samp, small, strike, strong, sub, sup, tt, var, b, u, i, center, dl, dt, dd, ol, ul, li, fieldset, form, label, legend, table, caption, tbody, tfoot, thead, tr, th, td { margin: 0; padding: 0; border: 0; outline: 0; font-size: 100%; vertical-align: baseline; background: transparent; font-family: "Trebuchet MS", Tahoma, Verdana, Arial, sans-serif; font-size: 14px; overflow: auto; } #vokiel_small_calendar { /* width: 327px; */ width: 427px; margin: 0 auto; background: #fff; overflow: auto; } #vokiel_small_calendar ul { border: 1px solid silver; padding: 0px 2px; } #vokiel_small_calendar ul, #vokiel_small_calendar ul li { list-style: none; overflow: auto; } #vokiel_small_calendar ul li{ margin: 2px 0px; padding: 2px 0px; text-align: right; } #vokiel_small_calendar ul li strong{ text-align: center; display: block; float: left; width: 59px; clear: left; border-right: 1px solid #fff; } #vokiel_small_calendar ul li span{ display: block; text-align: center; float: left; width: 40px; border-right: 1px solid #fff; cursor: pointer; } #vokiel_small_calendar .days_31 { background: #46A12A; color: #fff; } #vokiel_small_calendar .days_30 { background: #F29400; color: #fff; } #vokiel_small_calendar .days_28, #vokiel_small_calendar .days_29 { background: #EA609C; color: #fff; } #vokiel_small_calendar table { border-collapse: collapse; float: right; } #vokiel_small_calendar table, #vokiel_small_calendar table tbody, #vokiel_small_calendar table tr{ width: 287px; } #vokiel_small_calendar table tr td{ text-align: center; border-right: 1px solid #fff; cursor: default; } #vokiel_small_calendar ul li.hover, #vokiel_small_calendar ul li span.hover, #vokiel_small_calendar ul li table tbody tr td.hover { background-color: #59ACEF; color: #fff; } #vokiel_small_calendar ul li .giveYear { float: right; width: 75px; text-align: center; } #vokiel_small_calendar ul li .giveYear #accept { width: 16px; height: 16px; vertical-align: middle; } #vokiel_small_calendar ul li .giveYear #year{ width: 35px; border: 1px solid silver; } #vokiel_small_calendar ul li .giveYear #year.error { border: 1px solid red; } #vokiel_small_calendar ul li .giveYear p { font-size: 12px; } #vokiel_small_calendar ul li .giveYear small { font-size: 10px; } |
Voila
This was written using PHP and JavaScript. That was the first idea, which was intended to integrate the calendar with important events. However, there is nothing wrong to rewrite the PHP part into JS. So we could obtain a calendar, which does not require server-side script.
In plans for an unspecified future I have a version without the participation of PHP, maybe packing this into an Opera widget, or desktop gadget in the Win 7
Troszkę słaby silnik tego kalendarza skoro generuje dla lutego 31 dni. I troszkę “animacja” – toggle – średnio działająca.
Hi dear, good job!!
But in the demo didn’t run the language!! :S
I think this my idea could be very usefull if it will became a desktop widjet: are you able to do so?
@piotroo89 nie generuje 31 dni dla lutego. Jak się dobrze przyjrzysz, to luty jest tego samego koloru, co 28 w tabeli dni. Styczeń, marzec, maj itd są tego samego koloru co 31 w tabeli dni, a kwiecień, czerwiec – co 30 w tabeli dni. Kolorowanie wierszy nie jest przypadkowe. Kolory tła odpowiadają ilościom dni. Tabela dni jest uniwersalna dla wszystkich miesięcy.
Grafish Design yes, there is problem with the demo, tomorrow I will fix it, thx for info.
I’m going to do a desktop widget, an also english version of this post 😉
edit: language error fixed
Ok dear, I wait for the widget!! Give me this present!! 🙂
P.s.
Oh, dear, don’t forget to develope the calendar traslated in 32 languages, for all the users of the world! 😛
Ahahahhahahahahahaha!! 🙂
Bye!
[…] jak zaplanowałem na końcu wpisu The Small Calendar – jQuery + PHP w praktyce, postanowiłem stworzyć systemowy (windowsowy) gadżet z The Small Calendar. W tym wpisie postaram […]