1// the semi-colon before function invocation is a safety net against concatenated 2// scripts and/or other plugins which may not be closed properly. 3;(function ($, window, document, undefined) { 4 5 "use strict"; 6 7 // Create the defaults once 8 var pluginName = "simpleCalendar", 9 defaults = { 10 months: ['january', 'february', 'march', 'april', 'may', 'june', 'july', 'august', 'september', 'october', 'november', 'december'], //string of months starting from january 11 days: ['sunday', 'monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday'], //string of days starting from sunday 12 displayYear: true, // display year in header 13 fixedStartDay: true, // Week begin always by monday or by day set by number 0 = sunday, 7 = saturday, false = month always begin by first day of the month 14 displayEvent: true, // display existing event 15 disableEventDetails: false, // disable showing event details 16 disableEmptyDetails: false, // disable showing empty date details 17 events: [], // List of event 18 onInit: function (calendar) {}, // Callback after first initialization 19 onMonthChange: function (month, year) {}, // Callback on month change 20 onDateSelect: function (date, events) {}, // Callback on date selection 21 onEventSelect: function () {}, // Callback fired when an event is selected - see $(this).data('event') 22 onEventCreate: function( $el ) {}, // Callback fired when an HTML event is created - see $(this).data('event') 23 onDayCreate: function( $el, d, m, y ) {} // Callback fired when an HTML day is created - see $(this).data('today'), .data('todayEvents') 24 }; 25 26 // The actual plugin constructor 27 function Plugin(element, options) { 28 this.element = element; 29 this.settings = $.extend({}, defaults, options); 30 this._defaults = defaults; 31 this._name = pluginName; 32 this.currentDate = new Date(); 33 this.init(); 34 } 35 36 function formatAMPM(date) { 37 var hours = date.getHours(); 38 var minutes = date.getMinutes(); 39 var ampm = hours >= 12 ? 'pm' : 'am'; 40 hours = hours % 12; 41 hours = hours ? hours : 12; // the hour '0' should be '12' 42 minutes = minutes < 10 ? '0'+minutes : minutes; 43 var strTime = hours + ':' + minutes + ' ' + ampm; 44 return strTime; 45 } 46 47 // Avoid Plugin.prototype conflicts 48 $.extend(Plugin.prototype, { 49 init: function () { 50 var container = $(this.element); 51 var todayDate = this.currentDate; 52 53 var calendar = $('<div class="calendar"></div>'); 54 var header = $('<header>' + 55 '<h2 class="month simple-calendar-headline"></h2>' + 56 '<a class="simple-calendar-btn btn-prev" href="#"></a>' + 57 '<a class="simple-calendar-btn btn-next" href="#"></a>' + 58 '</header>'); 59 60 this.updateHeader(todayDate, header); 61 calendar.append(header); 62 63 this.buildCalendar(todayDate, calendar); 64 container.append(calendar); 65 66 this.bindEvents(); 67 this.settings.onInit(this); 68 }, 69 70 //Update the current month header 71 updateHeader: function (date, header) { 72 var monthText = this.settings.months[date.getMonth()]; 73 monthText += this.settings.displayYear ? ' <div class="year">' + date.getFullYear() : '</div>'; 74 header.find('.month').html(monthText); 75 }, 76 77 //Build calendar of a month from date 78 buildCalendar: function (fromDate, calendar) { 79 var plugin = this; 80 81 calendar.find('table').remove(); 82 83 var body = $('<table></table>'); 84 var thead = $('<thead></thead>'); 85 var tbody = $('<tbody></tbody>'); 86 87 //setting current year and month 88 var y = fromDate.getFullYear(), m = fromDate.getMonth(); 89 90 //first day of the month 91 var firstDay = new Date(y, m, 1); 92 //last day of the month 93 var lastDay = new Date(y, m + 1, 0); 94 // Start day of weeks 95 var startDayOfWeek = firstDay.getDay(); 96 97 if (this.settings.fixedStartDay !== false) { 98 // Backward compatibility 99 startDayOfWeek = this.settings.fixedStartDay === true ? 1 : this.settings.fixedStartDay; 100 101 // If first day of month is different of startDayOfWeek 102 while (firstDay.getDay() !== startDayOfWeek) { 103 firstDay.setDate(firstDay.getDate() - 1); 104 } 105 // If last day of month is different of startDayOfWeek + 7 106 while (lastDay.getDay() !== ((startDayOfWeek + 6) % 7)) { 107 lastDay.setDate(lastDay.getDate() + 1); 108 } 109 } 110 111 //Header day in a week ( (x to x + 7) % 7 to start the week by monday if x = 1) 112 for (var i = startDayOfWeek; i < startDayOfWeek + 7; i++) { 113 thead.append($('<td>' + this.settings.days[i % 7].substring(0, 3) + '</td>')); 114 } 115 116 //For firstDay to lastDay 117 for (var day = firstDay; day <= lastDay; day.setDate(day.getDate())) { 118 var tr = $('<tr></tr>'); 119 //For each row 120 for (var i = 0; i < 7; i++) { 121 var td = $('<td><div class="day" data-date="' + day.toISOString() + '">' + day.getDate() + '</div></td>'); 122 123 var $day = td.find('.day'); 124 125 //if today is this day 126 if (day.toDateString() === (new Date).toDateString()) { 127 $day.addClass("today"); 128 } 129 130 //if day is not in this month 131 if (day.getMonth() != fromDate.getMonth()) { 132 $day.addClass("wrong-month"); 133 } 134 135 // filter today's events 136 var todayEvents = plugin.getDateEvents(day); 137 138 if (todayEvents.length && plugin.settings.displayEvent) { 139 $day.addClass(plugin.settings.disableEventDetails ? "has-event disabled" : "has-event"); 140 } else { 141 $day.addClass(plugin.settings.disableEmptyDetails ? "disabled" : ""); 142 } 143 144 // associate some data available from the onDayCreate callback 145 $day.data( 'todayEvents', todayEvents ); 146 147 // simplify further customization 148 this.settings.onDayCreate( $day, day.getDate(), m, y ); 149 150 tr.append(td); 151 day.setDate(day.getDate() + 1); 152 } 153 tbody.append(tr); 154 } 155 156 body.append(thead); 157 body.append(tbody); 158
159 var eventContainer = $('<div class="event-container"><div class="close"></div><div class="event-wrapper"></div></div>'); 160 161 calendar.append(body); 162 calendar.append(eventContainer); 163 }, 164 changeMonth: function (value) { 165 this.currentDate.setMonth(this.currentDate.getMonth() + value, 1); 166 this.buildCalendar(this.currentDate, $(this.element).find('.calendar')); 167 this.updateHeader(this.currentDate, $(this.element).find('.calendar header')); 168 this.settings.onMonthChange(this.currentDate.getMonth(), this.currentDate.getFullYear()) 169 }, 170 //Init global events listeners 171 bindEvents: function () { 172 var plugin = this; 173 174 //Remove previously created events 175 $(plugin.element).off(); 176 177 //Click previous month 178 $(plugin.element).on('click', '.btn-prev', function ( e ) { 179 plugin.changeMonth(-1) 180 e.preventDefault(); 181 }); 182 183 //Click next month 184 $(plugin.element).on('click', '.btn-next', function ( e ) { 185 plugin.changeMonth(1); 186 e.preventDefault(); 187 }); 188 189 //Binding day event 190 $(plugin.element).on('click', '.day', function (e) { 191 var date = new Date($(this).data('date')); 192 var events = plugin.getDateEvents(date); 193 if (!$(this).hasClass('disabled')) { 194 plugin.fillUp(e.pageX, e.pageY); 195 plugin.displayEvents(events); 196 } 197 plugin.settings.onDateSelect(date, events); 198 }); 199 200 //Binding event container close 201 $(plugin.element).on('click', '.event-container .close', function (e) { 202 plugin.empty(e.pageX, e.pageY); 203 }); 204 }, 205 206 displayEvents: function (events) { 207 var plugin = this; 208 var container = $(this.element).find('.event-wrapper'); 209 210 events.forEach(function (event) { 211 var startDate = new Date(event.startDate); 212 var endDate = new Date(event.endDate); 213 var $event = $('' + 214 '<div class="event">' + 215 // ' <div class="event-hour">' + startDate.getHours() + ':' + (startDate.getMinutes() < 10 ? '0' : '') + startDate.getMinutes() + '</div>' + 216 ' <div class="event-hour">' + formatAMPM(startDate) + '</div>' + 217 ' <div class="event-date">' + plugin.formatDateEvent(startDate, endDate) + '</div>' + 218 ' <div class="event-summary">' + event.summary + '</div>' + 219 '</div>'); 220 221 $event.data( 'event', event ); 222 $event.click( plugin.settings.onEventSelect ); 223 224 // simplify further customization 225 plugin.settings.onEventCreate( $event ); 226 227 container.append($event); 228 }) 229 }, 230 addEvent: function(newEvent) { 231 var plugin = this; 232 // add the new event to events list 233 plugin.settings.events = [...plugin.settings.events, newEvent] 234 this.buildCalendar(this.currentDate, $(this.element).find('.calendar')); 235 }, 236 setEvents: function(newEvents) { 237 var plugin = this; 238 // add the new event to events list 239 plugin.settings.events = newEvents 240 this.buildCalendar(this.currentDate, $(this.element).find('.calendar')); 241 }, 242 //Small effect to fillup a container 243 fillUp: function (x, y) { 244 var plugin = this; 245 var elem = $(plugin.element); 246 var elemOffset = elem.offset(); 247 248 var filler = $('<div class="filler" style=""></div>'); 249 filler.css("left", x - elemOffset.left); 250 filler.css("top", y - elemOffset.top); 251 252 elem.find('.calendar').append(filler); 253 254 filler.animate({ 255 width: "300%", 256 height: "300%" 257 }, 500, function () { 258 elem.find('.event-container').show(); 259 filler.hide(); 260 }); 261 }, 262 //Small effect to empty a container 263 empty: function (x, y) { 264 var plugin = this; 265 var elem = $(plugin.element); 266 var elemOffset = elem.offset(); 267 268 var filler = elem.find('.filler'); 269 filler.css("width", "300%"); 270 filler.css("height", "300%"); 271 272 filler.show(); 273 274 elem.find('.event-container').hide().find('.event').remove(); 275 276 filler.animate({ 277 width: "0%", 278 height: "0%" 279 }, 500, function () { 280 filler.remove(); 281 }); 282 }, 283 getDateEvents: function (d) { 284 var plugin = this; 285 return plugin.settings.events.filter(function (event) { 286 return plugin.isDayBetween(new Date(d), new Date(event.startDate), new Date(event.endD
286ate)); 287 }); 288 }, 289 isDayBetween: function (d, dStart, dEnd) { 290 dStart.setHours(0,0,0); 291 dEnd.setHours(23,59,59,999); 292 d.setHours(12,0,0); 293 294 return dStart <= d && d <= dEnd; 295 }, 296 formatDateEvent: function (dateStart, dateEnd) { 297 var formatted = ''; 298 formatted += this.settings.days[dateStart.getDay()] + ' - ' + dateStart.getDate() + ' ' + this.settings.months[dateStart.getMonth()].substring(0, 3); 299 300 if (dateEnd.getDate() !== dateStart.getDate()) { 301 formatted += ' to ' + dateEnd.getDate() + ' ' + this.settings.months[dateEnd.getMonth()].substring(0, 3) 302 } 303 return formatted; 304 } 305 }); 306 307 // A really lightweight plugin wrapper around the constructor, 308 // preventing against multiple instantiations 309 $.fn[pluginName] = function (options) { 310 return this.each(function () { 311 if (!$.data(this, "plugin_" + pluginName)) { 312 $.data(this, "plugin_" + pluginName, new Plugin(this, options)); 313 } 314 }); 315 }; 316})(jQuery, window, document);
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.