1/*! 2 * Evo Calendar - Simple and Modern-looking Event Calendar Plugin 3 * 4 * Licensed under the MIT License 5 * 6 * Version: 1.1.3 7 * Author: Edlyn Villegas 8 * Docs: https://edlynvillegas.github.com/evo-calendar 9 * Repo: https://github.com/edlynvillegas/evo-calendar 10 * Issues: https://github.com/edlynvillegas/evo-calendar/issues 11 * 12 */ 13 14;(function(factory) { 15 'use strict'; 16 if (typeof define === 'function' && define.amd) { 17 define(['jquery'], factory); 18 } else if (typeof exports !== 'undefined') { 19 module.exports = factory(require('jquery')); 20 } else { 21 factory(jQuery); 22 } 23 24}(function($) { 25 'use strict'; 26 var EvoCalendar = window.EvoCalendar || {}; 27 28 EvoCalendar = (function() { 29 var instanceUid = 0; 30 function EvoCalendar(element, settings) { 31 var _ = this; 32 _.defaults = { 33 theme: null, 34 format: 'mm/dd/yyyy', 35 titleFormat: 'MM yyyy', 36 eventHeaderFormat: 'MM d, yyyy', 37 firstDayOfWeek: 0, 38 language: 'en', 39 todayHighlight: false, 40 sidebarDisplayDefault: true, 41 sidebarToggler: true, 42 eventDisplayDefault: true, 43 eventListToggler: true, 44 calendarEvents: null 45 }; 46 _.options = $.extend({}, _.defaults, settings); 47 48 _.initials = { 49 default_class: $(element)[0].classList.value, 50 validParts: /dd?|DD?|mm?|MM?|yy(?:yy)?/g, 51 dates: { 52 en: { 53 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"], 54 // daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"], 55 daysShort: ["S", "M", "T", "W", "T", "F", "S"], 56 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"], 57 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "
57November", "December"], 58 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"], 59 noEventForToday: "No event today.", 60 noEventForThisDay: "No event for this day.", 61 previousYearText: "Previous year", 62 nextYearText: "Next year", 63 closeSidebarText: "Close sidebar", 64 closeEventListText: "Close event list" 65 }, 66 es: { 67 days: ["Domingo", "Lunes", "Martes", "Miércoles", "Jueves", "Viernes", "Sábado"], 68 daysShort: ["Dom", "Lun", "Mar", "Mié", "Jue", "Vie", "Sáb"], 69 daysMin: ["Do", "Lu", "Ma", "Mi", "Ju", "Vi", "Sa"], 70 months: ["Enero", "Febrero", "Marzo", "Abril", "Mayo", "Junio", "Julio", "Agosto", "Septiembre", "Octubre", "Noviembre", "Diciembre"], 71 monthsShort: ["Ene", "Feb", "Mar", "Abr", "May", "Jun", "Jul", "Ago", "Sep", "Oct", "Nov", "Dic"], 72 noEventForToday: "No hay evento para hoy.. ¡asà que descanse! :)", 73 noEventForThisDay: "Ningún evento para este dÃa.. ¡asà que descanse! :)", 74 previousYearText: "Año anterior", 75 nextYearText: "El próximo año", 76 closeSidebarText: "Cerrar la barra lateral", 77 closeEventListText: "Cerrar la lista de eventos" 78 }, 79 de: { 80 days: ["Sonntag", "Montag", "Dienstag", "Mittwoch", "Donnerstag", "Freitag", "Samstag"], 81 daysShort: ["So", "Mo", "Di", "Mi", "Do", "Fr", "Sa"], 82 daysMin: ["So", "Mo", "Di", "Mi", "Do", "Fr", "Sa"], 83 months: ["Januar", "Februar", "März", "April", "Mai", "Juni", "Juli", "August", "September", "Oktober", "November", "Dezember"], 84 monthsShort: ["Jan", "Feb", "Mär", "Apr", "Mai", "Jun", "Jul", "Aug", "Sep", "Okt", "Nov", "Dez"], 85 noEventForToday: "Keine Veranstaltung für heute.. also ruhen Sie sich aus! :)", 86 noEventForThisDay: "Keine Veranstaltung für diesen Tag.. also ruhen Sie sich aus! :)", 87 previousYearText: "Vorheriges Jahr", 88 nextYearText: "Nächstes Jahr", 89 closeSidebarText: "SchlieÃen Sie die Seitenleiste", 90 closeEventListText: "SchlieÃen Sie die Ereignisliste" 91 }, 92 pt: { 93 days: ["Domingo", "Segunda-Feira", "Terça-Feira", "Quarta-Feira", "Quinta-Feira", "Sexta-Feira", "Sábado"], 94 daysShort: ["Dom", "Seg", "Ter", "Qua", "Qui", "Sex", "Sáb"], 95 daysMin: ["Do", "2a", "3a", "4a", "5a", "6a", "Sa"], 96 months: ["Janeiro", "Fevereiro", "Março", "Abril", "Maio", "Junho", "Julho", "Agosto", "Setembro", "Outubro", "Novembro", "Dezembro"], 97 monthsShort: ["Jan", "Feb", "Mar", "Abr", "Mai", "Jun", "Jul", "Ago", "Set", "Out", "Nov", "Dez"], 98 noEventForToday: "Nenhum evento para hoje.. então descanse! :)", 99 noEventForThisDay: "Nenhum evento para este dia.. então descanse! :)", 100 previousYearText: "Ano anterior", 101 nextYearText: "Próximo ano", 102 closeSidebarText: "Feche a barra lateral", 103 closeEventListText: "Feche a lista de eventos" 104 }, 105 fr: { 106 days: ["Dimanche", "Lundi", "Mardi", "Mercredi", "Jeudi", "Vendredi", "Samedi"], 107 daysShort: ["Dim", "Lun", "Mar", "Mer", "Jeu", "Ven", "Sam"], 108 daysMin: ["Di", "Lu", "Ma", "Me", "Je", "Ve", "Sa"], 109 months: ["Janvier", "Février", "Mars", "Avril", "Mai", "Juin", "Juillet", "Août", "Septembre", "Octobre", "Novembre", "Décembre"], 110 monthsShort: ["Jan", "Fév", "Mar", "Avr", "Mai", "Juin", "Juil", "Août", "Sept", "Oct", "Nov", "Déc"], 111 noEventForToday: "Rien pour aujourd'hui... Belle journée :)", 112 noEventForThisDay: "Rien pour ce jour-ci... Profite de te réposer :)", 113 previousYearText: "Année précédente", 114 nextYearText: "L'année prochaine", 115 closeSidebarText: "Fermez la barre latérale", 116 closeEventListText: "Fermer la liste des événements" 117 }, 118 nl: { 119 days: ["Zondag", "Maandag", "Dinsdag", "Woensdag", "Donderdag", "Vrijdag", "Zaterdag"], 120 daysShort: ["Zon", "Maan", "Din", "Woe", "Don", "Vrij", "Zat"],
121 daysMin: ["Zo", "Ma", "Di", "Wo", "Do", "Vr", "Za"], 122 months: ["Januari", "Februari", "Maart", "April", "Mei", "Juni", "Juli", "Augustus", "September", "Oktober", "November", "December"], 123 monthsShort: ["Jan", "Feb", "Mar", "Apr", "Mei", "Jun", "Jul", "Aug", "Sep", "Okt", "Nov", "Dec"], 124 noEventForToday: "Geen event voor vandaag.. dus rust even uit! :)", 125 noEventForThisDay: "Geen event voor deze dag.. dus rust even uit! :)", 126 previousYearText: "Vorig jaar", 127 nextYearText: "Volgend jaar", 128 closeSidebarText: "Sluit de zijbalk", 129 closeEventListText: "Sluit de event lijst" 130 }, 131 id: { 132 days: ["Minggu", "Senin", "Selasa", "Rabu", "Kamis", "Jumat", "Sabtu"], 133 daysShort: ["Min", "Sen", "Sel", "Rab", "Kam", "Jum", "Sab"], 134 daysMin: ["Mi", "Sn", "Sl", "Ra", "Ka", "Ju", "Sa"], 135 months: ["Januari", "Februari", "Maret", "April", "Mei", "Juni", "Juli", "Agustus", "September", "Oktober", "November", "Desember"], 136 monthsShort: ["Jan", "Feb", "Mar", "Apr", "Mei", "Jun", "Jul", "Agu", "Sep", "Okt", "Nov", "Des"], 137 noEventForToday: "Tidak ada Acara untuk Sekarang.. Jadi Beristirahatlah! :)", 138 noEventForThisDay: "Tidak ada Acara untuk Hari Ini.. Jadi Beristirahatlah! :)", 139 previousYearText: "Tahun Sebelumnya", 140 nextYearText: "Tahun Berikutnya", 141 closeSidebarText: "Tutup Sidebar", 142 closeEventListText: "Tutup Daftar Acara" 143 } 144 } 145 } 146 _.initials.weekends = { 147 sun: _.initials.dates[_.options.language].daysShort[0], 148 sat: _.initials.dates[_.options.language].daysShort[6] 149 } 150 151 152 // Format Calendar Events into selected format 153 if(_.options.calendarEvents != null) { 154 for(var i=0; i < _.options.calendarEvents.length; i++) { 155 // If event doesn't have an id, throw an error message 156 if(!_.options.calendarEvents[i].id) { 157 console.log("%c Event named: \""+_.options.calendarEvents[i].name+"\" doesn't have a unique ID ", "color:white;font-weight:bold;background-color:#e21d1d;"); 158 } 159 if(_.isValidDate(_.options.calendarEvents[i].date)) { 160 _.options.calendarEvents[i].date = _.formatDate(_.options.calendarEvents[i].date, _.options.format) 161 } 162 } 163 } 164 165 // Global variables 166 _.startingDay = null; 167 _.monthLength = null; 168 _.windowW = $(window).width(); 169 170 // CURRENT 171 _.$current = { 172 month: (isNaN(this.month) || this.month == null) ? new Date().getMonth() : this.month, 173 year: (isNaN(this.year) || this.year == null) ? new Date().getFullYear() : this.year, 174 date: _.formatDate(_.initials.dates[_.defaults.language].months[new Date().getMonth()]+' '+new Date().getDate()+' '+ new Date().getFullYear(), _.options.format) 175 } 176 177 // ACTIVE 178 _.$active = { 179 month: _.$current.month, 180 year: _.$current.year, 181 date: _.$current.date, 182 event_date: _.$current.date, 183 events: [] 184 } 185 186 // LABELS 187 _.$label = { 188 days: [], 189 months: _.initials.dates[_.defaults.language].months, 190 days_in_month: [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31] 191 } 192 193 // HTML Markups (template) 194 _.$markups = { 195 calendarHTML: '', 196 mainHTML: '', 197 sidebarHTML: '', 198 eventHTML: '' 199 } 200 // HTML DOM elements 201 _.$elements = { 202 calendarEl: $(element), 203 innerEl: null, 204 sidebarEl: null, 205 eventEl: null, 206 207 sidebarToggler: null, 208 eventListToggler: null, 209 210 activeDayEl: null, 211 activeMonthEl: null, 212 activeYearEl: null 213 } 214 _.$breakpoints = { 215 tablet: 768, 216 mobile: 425 217 } 218 _.$UI = { 219 hasSidebar: true, 220 hasEvent: true 221 } 222 223 _.formatDate = $.proxy(_.formatDate, _); 224 _.selectDate = $.proxy(_.selectDate, _); 225 _.selectMonth = $.proxy(_.selectMonth, _); 226 _.selectYear = $.proxy(_.selectYear, _); 227 _.selectEvent = $.proxy(_.selectEvent, _); 228 _.toggleSidebar = $.proxy(_.toggleSidebar, _); 229 _.toggleEventList = $.proxy(_.toggleEventList, _); 230 231 _.instanceUid = instanceUid++; 232 233 _.init(true); 234 } 235 236 return EvoCalendar; 237 238 }()); 239 240 // v1.0.0 - Initialize plugin 241 EvoCalendar.prototype.init = function(init) { 242 var _ = this; 243 244 if (!$(_.$elements.calendarEl).hasClass('calendar-initialized')) { 245 $(_.$elements.calendarEl).addClass('evo-calendar calendar-initialized'); 246 if (_.windowW <= _.$breakpoints.tablet) { // tablet/mobile 247 _.toggleSidebar(false); 248 _.toggleEventList(false); 249 } else { 250 if (!_.options.sidebarDisplayDefault) _.toggleSidebar(false); 251 else _.toggleSidebar(true); 252 253 if (!_.options.eventDisplayDefault) _.toggleEventList(false); 254 else _.toggleEventList(true); 255 } 256 if (_.options.theme) _.setTheme(_.options.theme); // set calendar theme 257 _.buildTheBones(); // start building the calendar components 258 } 259 }; 260 // v1.0.0 - Destroy plugin 261 EvoCalendar.prototype.destroy = function() { 262 var _ = this; 263 // code here 264 _.destroyEventListener(); 265 if (_.$elements.calendarEl) { 266 _.$elements.calendarEl.removeClass('calendar-initialized'); 267 _.$elements.calendarEl.removeClass('evo-calendar'); 268 _.$elements.calendarEl.removeClass('sidebar-hide'); 269 _.$elements.calendarEl.removeClass('event-hide'); 270 } 271 _.$elements.calendarEl.empty(); 272 _.$elements.calendarEl.attr('class', _.initials.default_class); 273 $(_.$elements.calendarEl).trigger("destroy", [_]) 274 } 275 276 // v1.0.0 - Limit title (...) 277 EvoCalendar.prototype.limitTitle = function(title, limit) { 278 var newTitle = []; 279 limit = limit === undefined ? 18 : limit; 280 if ((title).split(' ').join('').length > limit) { 281 var t = title.split(' '); 282 for (var i=0; i<t.length; i++) { 283 if (t[i].length + newTitle.join('').length <= limit) { 284 newTitle.push(t[i]) 285 } 286 } 287 return newTitle.join(' ') + '...' 288 } 289 return title; 290 } 291 292 // v1.1.2 - Check and filter strings 293 EvoCalendar.prototype.stringCheck = function(d) { 294 return d.replace(/[^\w]/g, '\\$&'); 295 } 296 297 // v1.0.0 - Parse format (date) 298 EvoCalendar.prototype.parseFormat = function(format) { 299 var _ = this; 300 if (typeof format.toValue === 'function' && typeof format.toDisplay === 'function') 301 return format; 302 // IE treats \0 as a string end in inputs (truncating the value), 303 // so it's a bad format delimiter, anyway 304 var separators = format.replace(_.initials.validParts, '\0').split('\0'), 305 parts = format.match(_.initials.validParts); 306 if (!separators || !separators.length || !parts || parts.length === 0){ 307 console.log("%c Invalid date format ", "color:white;font-weight:bold;background-color:#e21d1d;"); 308 } 309 return {separators: separators, parts: parts}; 310 }; 311 312 // v1.0.0 - Format date 313 EvoCalendar.prototype.formatDate = function(date, format, language) { 314 var _ = this; 315 if (!date) 316 return ''; 317 language = language ? language : _.defaults.language 318 if (typeof format === 'string') 319 format = _.parseFormat(format); 320 if (format.toDisplay) 321 return format.toDisplay(date, format, language); 322 323 var ndate = new Date(date); 324 // if (!_.isValidDate(ndate)) { // test 325 // ndate = new Date(date.replace(/-/g, '/')) 326 // } 327 328 var val = { 329 d: ndate.getDate(), 330 D: _.initials.dates[language].daysShort[ndate.getDay()], 331 DD: _.initials.dates[language].days[ndate.getDay()], 332 m: ndate.getMonth() + 1, 333 M: _.initials.dates[language].monthsShort[ndate.getMonth()], 334 MM: _.initials.dates[language].months[ndate.getMonth()], 335 yy: ndate.getFullYear().toString().substring(2), 336 yyyy: ndate.getFullYear() 337 }; 338 339 val.dd = (val.d < 10 ? '0' : '') + val.d; 340 val.mm = (val.m < 10 ? '0' : '') + val.m; 341 date = []; 342 var seps = $.extend([], format.separators); 343 for (var i=0, cnt = format.parts.length; i <= cnt; i++){ 344 if (seps.length) 345 date.push(seps.shift()); 346 date.push(val[format.parts[i]]); 347 } 348 return date.join(''); 349 }; 350 351 // v1.0.0 - Get dates between two dates 352 EvoCalendar.prototype.getBetweenDates = function(dates) { 353 var _ = this, betweenDates = []; 354 for (var x = 0; x < _.monthLength; x++) { 355 var active_date = _.formatDate(_.$label.months[_.$active.month] +' '+ (x + 1) +' '+ _.$active.year, _.options.format); 356 if (_.isBetweenDates(active_date, dates)) { 357 betweenDates.push(active_date); 358 } 359 } 360 return betweenDates; 361 }; 362 363 // v1.0.0 - Check if date is between the passed calendar date 364 EvoCalendar.prototype.isBetweenDates = function(active_date, dates) { 365 var sd, ed; 366 if (dates instanceof Array) { 367 sd = new Date(dates[0]); 368 ed = new Date(dates[1]); 369 } else { 370 sd = new Date(dates); 371 ed = new Date(dates); 372 } 373 if (sd <= new Date(active_date) && ed >= new Date(active_date)) { 374 return true; 375 } 376 return false;
377 } 378 379 // v1.0.0 - Check if event has the same event type in the same date 380 EvoCalendar.prototype.hasSameDayEventType = function(date, type) { 381 var _ = this, eventLength = 0; 382 383 for (var i = 0; i < _.options.calendarEvents.length; i++) { 384 if (_.options.calendarEvents[i].date instanceof Array) { 385 var arr = _.getBetweenDates(_.options.calendarEvents[i].date); 386 for (var x = 0; x < arr.length; x++) { 387 if(date === arr[x] && type === _.options.calendarEvents[i].type) { 388 eventLength++; 389 } 390 } 391 } else { 392 if(date === _.options.calendarEvents[i].date && type === _.options.calendarEvents[i].type) { 393 eventLength++; 394 } 395 } 396 } 397 398 if (eventLength > 0) { 399 return true; 400 } 401 return false; 402 } 403 404 // v1.0.0 - Set calendar theme 405 EvoCalendar.prototype.setTheme = function(themeName) { 406 var _ = this; 407 var prevTheme = _.options.theme; 408 _.options.theme = themeName.toLowerCase().split(' ').join('-'); 409 410 if (_.options.theme) $(_.$elements.calendarEl).removeClass(prevTheme); 411 if (_.options.theme !== 'default') $(_.$elements.calendarEl).addClass(_.options.theme); 412 } 413 414 // v1.0.0 - Called in every resize 415 EvoCalendar.prototype.resize = function() { 416 var _ = this; 417 _.windowW = $(window).width(); 418 419 if (_.windowW <= _.$breakpoints.tablet) { // tablet 420 _.toggleSidebar(false); 421 _.toggleEventList(false); 422 423 if (_.windowW <= _.$breakpoints.mobile) { // mobile 424 $(window) 425 .off('click.evocalendar.evo-' + _.instanceUid) 426 } else { 427 $(window) 428 .on('click.evocalendar.evo-' + _.instanceUid, $.proxy(_.toggleOutside, _)); 429 } 430 } else { 431 if (!_.options.sidebarDisplayDefault) _.toggleSidebar(false); 432 else _.toggleSidebar(true); 433 434 if (!_.options.eventDisplayDefault) _.toggleEventList(false); 435 else _.toggleEventList(true); 436 437 $(window) 438 .off('click.evocalendar.evo-' + _.instanceUid); 439 } 440 } 441 442 // v1.0.0 - Initialize event listeners 443 EvoCalendar.prototype.initEventListener = function() { 444 var _ = this; 445 446 // resize 447 $(window) 448 .off('resize.evocalendar.evo-' + _.instanceUid) 449 .on('resize.evocalendar.evo-' + _.instanceUid, $.proxy(_.resize, _)); 450 451 // IF sidebarToggler: set event listener: toggleSidebar 452 if(_.options.sidebarToggler) { 453 _.$elements.sidebarToggler 454 .off('click.evocalendar') 455 .on('click.evocalendar', _.toggleSidebar); 456 } 457 458 // IF eventListToggler: set event listener: toggleEventList 459 if(_.options.eventListToggler) { 460 _.$elements.eventListToggler 461 .off('click.evocalendar') 462 .on('click.evocalendar', _.toggleEventList); 463 } 464 465 // set event listener for each month 466 _.$elements.sidebarEl.find('[data-month-val]') 467 .off('click.evocalendar') 468 .on('click.evocalendar', _.selectMonth); 469 470 // set event listener for year 471 _.$elements.sidebarEl.find('[data-year-val]') 472 .off('click.evocalendar') 473 .on('click.evocalendar', _.selectYear); 474 475 // set event listener for every event listed 476 _.$elements.eventEl.find('[data-event-index]') 477 .off('click.evocalendar') 478 .on('click.evocalendar', _.selectEvent); 479 }; 480 481 // v1.0.0 - Destroy event listeners 482 EvoCalendar.prototype.destroyEventListener = function() { 483 var _ = this; 484 485 $(window).off('resize.evocalendar.evo-' + _.instanceUid); 486 $(window).off('click.evocalendar.evo-' + _.instanceUid); 487 488 // IF sidebarToggler: remove event listener: toggleSidebar 489 if(_.options.sidebarToggler) { 490 _.$elements.sidebarToggler 491 .off('click.evocalendar'); 492 } 493 494 // IF eventListToggler: remove event listener: toggleEventList 495 if(_.options.eventListToggler) { 496 _.$elements.eventListToggler 497 .off('click.evocalendar'); 498 } 499 500 // remove event listener for each day 501 _.$elements.innerEl.find('.calendar-day').children() 502 .off('click.evocalendar') 503 504 // remove event listener for each month 505 _.$elements.sidebarEl.find('[data-month-val]') 506 .off('click.evocalendar'); 507 508 // remove event listener for year 509 _.$elements.sidebarEl.find('[data-year-val]') 510 .off('click.evocalendar'); 511 512 // remove event listener for every event listed 513 _.$elements.eventEl.find('[data-event-index]') 514 .off('click.evocalendar'); 515 }; 516 517 // v1.0.0 - Calculate days (incl. monthLength, startingDays based on :firstDayOfWeekName) 518 EvoCalendar.prototype.calculateDays = function() { 519 var _ = this, nameDays, weekStart, firstDay; 520 _.monthLength = _.$label.days_in_month[_.$active.month];
520 // find number of days in month 521 if (_.$active.month == 1) { // compensate for leap year - february only! 522 if((_.$active.year % 4 == 0 && _.$active.year % 100 != 0) || _.$active.year % 400 == 0){ 523 _.monthLength = 29; 524 } 525 } 526 nameDays = _.initials.dates[_.options.language].daysShort; 527 weekStart = _.options.firstDayOfWeek; 528 529 while (_.$label.days.length < nameDays.length) { 530 if (weekStart == nameDays.length) { 531 weekStart=0; 532 } 533 _.$label.days.push(nameDays[weekStart]); 534 weekStart++; 535 } 536 firstDay = new Date(_.$active.year, _.$active.month).getDay() - weekStart; 537 _.startingDay = firstDay < 0 ? (_.$label.days.length + firstDay) : firstDay; 538 } 539 540 // v1.0.0 - Build the bones! (incl. sidebar, inner, events), called once in every initialization 541 EvoCalendar.prototype.buildTheBones = function() { 542 var _ = this; 543 _.calculateDays(); 544 545 if (!_.$elements.calendarEl.html()) { 546 var markup; 547 548 // --- BUILDING MARKUP BEGINS --- // 549 550 // sidebar 551 markup = '<div class="calendar-sidebar">'+ 552 '<div class="calendar-year">'+ 553 '<button class="icon-button" role="button" data-year-val="prev" title="'+_.initials.dates[_.options.language].previousYearText+'">'+ 554 '<span class="chevron-arrow-left"></span>'+ 555 '</button>'+ 556 ' <p></p> '+ 557 '<button class="icon-button" role="button" data-year-val="next" title="'+_.initials.dates[_.options.language].nextYearText+'">'+ 558 '<span class="chevron-arrow-right"></span>'+ 559 '</button>'+ 560 '</div><div class="month-list">'+ 561 '<ul class="calendar-months">'; 562 for(var i = 0; i < _.$label.months.length; i++) { 563 markup += '<li class="month" role="button" data-month-val="'+i+'">'+_.initials.dates[_.options.language].months[i]+'</li>'; 564 } 565 markup += '</ul>'; 566 markup += '</div></div>'; 567 568 // inner 569 markup += '<div class="calendar-inner">'+ 570 '<table class="calendar-table">'+ 571 '<tr><th colspan="7"></th></tr>'+ 572 '<tr class="calendar-header">'; 573 for(var i = 0; i < _.$label.days.length; i++ ){ 574 var headerClass = "calendar-header-day"; 575 if (_.$label.days[i] === _.initials.weekends.sat || _.$label.days[i] === _.initials.weekends.sun) { 576 headerClass += ' --weekend'; 577 } 578 markup += '<td class="'+headerClass+'">'+_.$label.days[i]+'</td>'; 579 } 580 markup += '</tr></table>'+ 581 '</div>'; 582 583 // events 584 markup += '<div class="calendar-events">'+ 585 '<div class="event-header"><p></p></div>'+ 586 '<div class="event-list"></div>'+ 587 '</div>'; 588 589 // --- Finally, build it now! --- // 590 _.$elements.calendarEl.html(markup); 591 592 if (!_.$elements.sidebarEl) _.$elements.sidebarEl = $(_.$elements.calendarEl).find('.calendar-sidebar'); 593 if (!_.$elements.innerEl) _.$elements.innerEl = $(_.$elements.calendarEl).find('.calendar-inner'); 594 if (!_.$elements.eventEl) _.$elements.eventEl = $(_.$elements.calendarEl).find('.calendar-events'); 595 596 // if: _.options.sidebarToggler 597 if(_.options.sidebarToggler) { 598 $(_.$elements.sidebarEl).append('<span id="sidebarToggler" role="button" aria-pressed title="'+_.initials.dates[_.options.language].closeSidebarText+'"><button class="icon-button"><span class="bars"></span></button></span>'); 599 if(!_.$elements.sidebarToggler) _.$elements.sidebarToggler = $(_.$elements.sidebarEl).find('span#sidebarToggler'); 600 } 601 if(_.options.eventListToggler) { 602 $(_.$elements.calendarEl).append('<span id="eventListToggler" role="button" aria-pressed title="'+_.initials.dates[_.options.language].closeEventListText+'"><button class="icon-button"><span class="chevron-arrow-right"></span></button></span>'); 603 if(!_.$elements.eventListToggler) _.$elements.eventListToggler = $(_.$elements.calendarEl).find('span#eventListToggler'); 604 } 605 } 606 607 _.buildSidebarYear(); 608 _.buildSidebarMonths();
609 _.buildCalendar(); 610 _.buildEventList(); 611 _.initEventListener(); // test 612 613 _.resize(); 614 } 615 616 // v1.0.0 - Build Event: Event list 617 EvoCalendar.prototype.buildEventList = function() { 618 var _ = this, markup, hasEventToday = false; 619 620 _.$active.events = []; 621 // Event date 622 var title = _.formatDate(_.$active.date, _.options.eventHeaderFormat, _.options.language); 623 _.$elements.eventEl.find('.event-header > p').text(title); 624 // Event list 625 var eventListEl = _.$elements.eventEl.find('.event-list'); 626 // Clear event list item(s) 627 if (eventListEl.children().length > 0) eventListEl.empty(); 628 if (_.options.calendarEvents) { 629 for (var i = 0; i < _.options.calendarEvents.length; i++) { 630 if(_.isBetweenDates(_.$active.date, _.options.calendarEvents[i].date)) { 631 eventAdder(_.options.calendarEvents[i]) 632 } 633 else if (_.options.calendarEvents[i].everyYear) { 634 var d = new Date(_.$active.date).getMonth() + 1 + ' ' + new Date(_.$active.date).getDate(); 635 var dd = new Date(_.options.calendarEvents[i].date).getMonth() + 1 + ' ' + new Date(_.options.calendarEvents[i].date).getDate(); 636 // var dates = [_.formatDate(_.options.calendarEvents[i].date[0], 'mm/dd'), _.formatDate(_.options.calendarEvents[i].date[1], 'mm/dd')]; 637 638 if(d==dd) { 639 eventAdder(_.options.calendarEvents[i]) 640 } 641 } 642 }; 643 } 644 function eventAdder(event) { 645 hasEventToday = true; 646 _.addEventList(event) 647 } 648 // IF: no event for the selected date 649 if(!hasEventToday) { 650 markup = '<div class="event-empty">'; 651 if (_.$active.date === _.$current.date) { 652 markup += '<p>'+_.initials.dates[_.options.language].noEventForToday+'</p>'; 653 } else { 654 markup += '<p>'+_.initials.dates[_.options.language].noEventForThisDay+'</p>'; 655 } 656 markup += '</div>'; 657 } 658 eventListEl.append(markup) 659 } 660 661 // v1.0.0 - Add single event to event list 662 EvoCalendar.prototype.addEventList = function(event_data) { 663 var _ = this, markup; 664 665 var external_icon = ((event_data.target == '_blank') ? ' <i class="external_icon fa fa-arrow-circle-o-up" aria-hidden="true"></i>' : ''); 666 var eventListEl = _.$elements.eventEl.find('.event-list'); 667 if (eventListEl.find('[data-event-index]').length === 0) eventListEl.empty(); 668 _.$active.events.push(event_data); 669 markup = '<div class="event-container" role="button" data-event-index="'+(event_data.id)+'">'; 670 markup += '<div class="event-icon"><div class="event-bullet-'+event_data.type+'"'; 671 if (event_data.color) { 672 markup += 'style="background-color:'+event_data.color+'"' 673 } 674 markup += '></div></div><div class="event-info"><a target="'+event_data.target+'" href="'+event_data.link_url+'"><p class="event-title">'+_.limitTitle(event_data.name, 200); 675 if (event_data.badge) markup += '<span>'+event_data.badge+'</span>'; 676 markup += external_icon + '</p>' 677 markup += '</a>' 678 if (event_data.description) markup += '<a target="'+event_data.target+'" href="'+event_data.link_url+'"><p class="event-desc">'+event_data.description+'</p></a>'; 679 markup += '</div>'; 680 markup += '</div>'; 681 eventListEl.append(markup); 682 683 _.$elements.eventEl.find('[data-event-index="'+(event_data.id)+'"]') 684 .off('click.evocalendar') 685 .on('click.evocalendar', _.selectEvent); 686 } 687 // v1.0.0 - Remove single event to event list 688 EvoCalendar.prototype.removeEventList = function(event_data) { 689 var _ = this, markup; 690 var eventListEl = _.$elements.eventEl.find('.event-list'); 691 if (eventListEl.find('[data-event-index="'+event_data+'"]').length === 0) return; // event not in active events 692 eventListEl.find('[data-event-index="'+event_data+'"]').remove(); 693 if (eventListEl.find('[data-event-index]').length === 0) { 694 eventListEl.empty(); 695 if (_.$active.date === _.$current.date) { 696 markup += '<p>'+_.initials.dates[_.options.language].noEventForToday+'</p>'; 697 } else { 698 markup += '<p>'+_.initials.dates[_.options.language].noEventForThisDay+'</p>'; 699 } 700 eventListEl.append(markup) 701 } 702 } 703 704 // v1.0.0 - Build Sidebar: Year text 705 EvoCalendar.prototype.buildSidebarYear = function() { 706 var _ = this; 707 708 _.$elements.sidebarEl.find('.calendar-year > p').text(_.$active.year); 709 } 710 711 // v1.0.0 - Build Sidebar: Months list text 712 EvoCalendar.prototype.buildSidebarMonths = function() { 713 var _ = this; 714 715 _.$elements.sidebarEl.find('.calendar-months > [data-month-val]').removeClass('active-month'); 716 _.$elements.sidebarEl.find('.calendar-months > [data-month-val="'+_.$active.month+'"]').addClass('active-month'); 717 } 718 719 // v1.0.0 - Build Calendar: Title, Days 720 EvoCalendar.prototype.buildCalendar = function() { 721 var _ = this, markup, title; 722 723 _.calculateDays(); 724 725 title = _.formatDate(new Date(_.$label.months[_.$active.month] +' 1 '+ _.$active.year), _.options.titleFormat, _.options.language); 726 _.$elements.innerEl.find('.calendar-table th').text(title); 727 728 _.$elements.innerEl.find('.calendar-body').remove(); // Clear days 729 730 markup += '<tr class="calendar-body">'; 731 var day = 1; 732 for (var i = 0; i < 9; i++) { // this loop is for is weeks (rows) 733 for (var j = 0; j < _.$label.days.length; j++) { // this loop is for weekdays (cells) 734 if (day <= _.monthLength && (i > 0 || j >= _.startingDay)) { 735 var dayClass = "calendar-day"; 736 if (_.$label.days[j] === _.initials.weekends.sat || _.$label.days[j] === _.initials.weekends.sun) { 737 dayClass += ' --weekend'; // add '--weekend' to sat sun 738 } 739 markup += '<td class="'+dayClass+'">'; 740 741 var thisDay = _.formatDate(_.$label.months[_.$active.month]+' '+day+' '+_.$active.year, _.options.format); 742 markup += '<div class="day" role="button" data-date-val="'+thisDay+'">'+day+'</div>'; 743 day++; 744 } else { 745 markup += '<td>'; 746 } 747 markup += '</td>'; 748 } 749 if (day > _.monthLength) { 750 break; // stop making rows if we've run out of days 751 } else { 752 markup += '</tr><tr class="calendar-body">'; // add if not 753 } 754 } 755 markup += '</tr>'; 756 _.$elements.innerEl.find('.calendar-table').append(markup); 757 758 if(_.options.todayHighlight) { 759 _.$elements.innerEl.find("[data-date-val='" + _.$current.date + "']").addClass('calendar-today'); 760 } 761 762 // set event listener for each day 763 _.$elements.innerEl.find('.calendar-day').children() 764 .off('click.evocalendar') 765 .on('click.evocalendar', _.selectDate) 766 767 var selectedDate = _.$elements.innerEl.find("[data-date-val='" + _.$active.date + "']"); 768 769 if (selectedDate) { 770 // Remove active class to all 771 _.$elements.innerEl.children().removeClass('calendar-active'); 772 // Add active class to selected date 773 selectedDate.addClass('calendar-active'); 774 } 775 if(_.options.calendarEvents != null) { // For event indicator (dots) 776 _.buildEventIndicator(); 777 } 778 }; 779 780 // v1.0.0 - Add event indicator/s (dots) 781 EvoCalendar.prototype.addEventIndicator = function(event) { 782 var _ = this, htmlToAppend, thisDate; 783 var event_date = event.date; 784 var type = _.stringCheck(event.type); 785 786 if (event_date instanceof Array) { 787 if (event.everyYear) { 788 for (var x=0; x<event_date.length; x++) { 789 event_date[x] = _.formatDate(new Date(event_date[x]).setFullYear(_.$active.year), _.options.format); 790 } 791 } 792 var active_date = _.getBetweenDates(event_date); 793 794 for (var i=0; i<active_date.length; i++) { 795 appendDot(active_date[i]); 796 } 797 } else { 798 if (event.everyYear) { 799 event_date = _.formatDate(new Date(event_date).setFullYear(_.$active.year), _.options.format); 800 } 801 appendDot(event_date); 802 } 803 804 function appendDot(date) { 805 thisDate = _.$elements.innerEl.find('[data-date-val="'+date+'"]'); 806 807 if (thisDate.find('span.event-indicator').length === 0) {
808 thisDate.append('<span class="event-indicator"></span>'); 809 } else { 810 thisDate.addClass('multiple'); 811 } 812 813 if (thisDate.find('span.event-indicator > .type-bullet > .type-'+type).length === 0) { 814 htmlToAppend = '<div class="type-bullet"><div '; 815 816 htmlToAppend += 'class="type-'+event.type+'"' 817 if (event.color) { htmlToAppend += 'style="background-color:'+event.color+'"' } 818 htmlToAppend += '></div></div>'; 819 thisDate.find('.event-indicator').append(htmlToAppend); 820 thisDate.addClass('has-indicator') 821 } 822 } 823 }; 824 825 // v1.0.0 - Remove event indicator/s (dots) 826 EvoCalendar.prototype.removeEventIndicator = function(event) { 827 var _ = this; 828 var event_date = event.date; 829 var type = _.stringCheck(event.type); 830 831 if (event_date instanceof Array) { 832 var active_date = _.getBetweenDates(event_date); 833 834 for (var i=0; i<active_date.length; i++) { 835 removeDot(active_date[i]); 836 } 837 } else { 838 removeDot(event_date); 839 } 840 841 function removeDot(date) { 842 // Check if no '.event-indicator', 'cause nothing to remove 843 if (_.$elements.innerEl.find('[data-date-val="'+date+'"] span.event-indicator').length === 0) { 844 return; 845 } 846 847 // // If has no type of event, then delete 848 if (!_.hasSameDayEventType(date, type)) { 849 _.$elements.innerEl.find('[data-date-val="'+date+'"] span.event-indicator > .type-bullet > .type-'+type).parent().remove(); 850 } 851 } 852 }; 853 854 /**************** 855 * METHODS * 856 ****************/ 857 858 // v1.0.0 - Build event indicator on each date 859 EvoCalendar.prototype.buildEventIndicator = function() { 860 var _ = this; 861 862 // prevent duplication 863 _.$elements.innerEl.find('.calendar-day > day > .event-indicator').empty(); 864 865 for (var i = 0; i < _.options.calendarEvents.length; i++) { 866 _.addEventIndicator(_.options.calendarEvents[i]); 867 } 868 }; 869 870 // v1.0.0 - Select event 871 EvoCalendar.prototype.selectEvent = function(event) { 872 var _ = this; 873 var el = $(event.target).closest('.event-container'); 874 var id = $(el).data('eventIndex').toString(); 875 var index = _.options.calendarEvents.map(function (event) { return (event.id).toString() }).indexOf(id); 876 var modified_event = _.options.calendarEvents[index]; 877 if (modified_event.date instanceof Array) { 878 modified_event.dates_range = _.getBetweenDates(modified_event.date); 879 } 880 $(_.$elements.calendarEl).trigger("selectEvent", [_.options.calendarEvents[index]]) 881 } 882 883 // v1.0.0 - Select year 884 EvoCalendar.prototype.selectYear = function(event) { 885 var _ = this; 886 var el, yearVal; 887 888 if (typeof event === 'string' || typeof event === 'number') { 889 if ((parseInt(event)).toString().length === 4) { 890 yearVal = parseInt(event); 891 } 892 } else { 893 el = $(event.target).closest('[data-year-val]'); 894 yearVal = $(el).data('yearVal'); 895 } 896 897 if(yearVal == "prev") { 898 --_.$active.year; 899 } else if (yearVal == "next") { 900 ++_.$active.year; 901 } else if (typeof yearVal === 'number') { 902 _.$active.year = yearVal; 903 } 904 905 if (_.windowW <= _.$breakpoints.mobile) { 906 if(_.$UI.hasSidebar) _.toggleSidebar(false); 907 } 908 909 $(_.$elements.calendarEl).trigger("selectYear", [_.$active.year]) 910 911 _.buildSidebarYear(); 912 _.buildCalendar(); 913 }; 914 915 // v1.0.0 - Select month 916 EvoCalendar.prototype.selectMonth = function(event) { 917 var _ = this; 918 919 if (typeof event === 'string' || typeof event === 'number') { 920 if (event >= 0 && event <=_.$label.months.length) { 921 // if: 0-11 922 _.$active.month = (event).toString(); 923 } 924 } else { 925 // if month is manually selected 926 _.$active.month = $(event.currentTarget).data('monthVal'); 927 } 928 929 _.buildSidebarMonths();
930 _.buildCalendar(); 931 932 if (_.windowW <= _.$breakpoints.tablet) { 933 if(_.$UI.hasSidebar) _.toggleSidebar(false); 934 } 935 936 // EVENT FIRED: selectMonth 937 $(_.$elements.calendarEl).trigger("selectMonth", [_.initials.dates[_.options.language].months[_.$active.month], _.$active.month]) 938 }; 939 940 // v1.0.0 - Select specific date 941 EvoCalendar.prototype.selectDate = function(event) { 942 var _ = this; 943 var oldDate = _.$active.date; 944 var date, year, month, activeDayEl, isSameDate; 945 946 if (typeof event === 'string' || typeof event === 'number' || event instanceof Date) { 947 date = _.formatDate(new Date(event), _.options.format) 948 year = new Date(date).getFullYear(); 949 month = new Date(date).getMonth(); 950 951 if (_.$active.year !== year) _.selectYear(year); 952 if (_.$active.month !== month) _.selectMonth(month); 953 activeDayEl = _.$elements.innerEl.find("[data-date-val='" + date + "']"); 954 } else { 955 activeDayEl = $(event.currentTarget); 956 date = activeDayEl.data('dateVal') 957 } 958 isSameDate = _.$active.date === date; 959 // Set new active date 960 _.$active.date = date; 961 _.$active.event_date = date; 962 // Remove active class to all 963 _.$elements.innerEl.find('[data-date-val]').removeClass('calendar-active'); 964 // Add active class to selected date 965 activeDayEl.addClass('calendar-active'); 966 // Build event list if not the same date events built 967 if (!isSameDate) _.buildEventList(); 968 969 // EVENT FIRED: selectDate 970 $(_.$elements.calendarEl).trigger("selectDate", [_.$active.date, oldDate]) 971 }; 972 973 // v1.0.0 - Return active date 974 EvoCalendar.prototype.getActiveDate = function() { 975 var _ = this; 976 return _.$active.date; 977 } 978 979 // v1.0.0 - Return active events 980 EvoCalendar.prototype.getActiveEvents = function() { 981 var _ = this; 982 return _.$active.events; 983 } 984 985 // v1.0.0 - Hide Sidebar/Event List if clicked outside 986 EvoCalendar.prototype.toggleOutside = function(event) { 987 var _ = this, isInnerClicked; 988 989 isInnerClicked = event.target === _.$elements.innerEl[0]; 990 991 if (_.$UI.hasSidebar && isInnerClicked) _.toggleSidebar(false); 992 if (_.$UI.hasEvent && isInnerClicked) _.toggleEventList(false); 993 } 994 995 // v1.0.0 - Toggle Sidebar 996 EvoCalendar.prototype.toggleSidebar = function(event) { 997 var _ = this; 998 999 if (event === undefined || event.originalEvent) { 1000 $(_.$elements.calendarEl).toggleClass('sidebar-hide'); 1001 _.$UI.hasSidebar = !_.$UI.hasSidebar; 1002 } else { 1003 if(event) { 1004 $(_.$elements.calendarEl).removeClass('sidebar-hide'); 1005 _.$UI.hasSidebar = true; 1006 } else { 1007 $(_.$elements.calendarEl).addClass('sidebar-hide'); 1008 _.$UI.hasSidebar = false; 1009 } 1010 } 1011 1012 if (_.windowW <= _.$breakpoints.tablet) { 1013 if (_.$UI.hasSidebar && _.$UI.hasEvent) _.toggleEventList(); 1014 } 1015 }; 1016 1017 // v1.0.0 - Toggle Event list 1018 EvoCalendar.prototype.toggleEventList = function(event) { 1019 var _ = this; 1020 1021 if (event === undefined || event.originalEvent) { 1022 $(_.$elements.calendarEl).toggleClass('event-hide'); 1023 _.$UI.hasEvent = !_.$UI.hasEvent; 1024 } else { 1025 if(event) { 1026 $(_.$elements.calendarEl).removeClass('event-hide'); 1027 _.$UI.hasEvent = true; 1028 } else { 1029 $(_.$elements.calendarEl).addClass('event-hide'); 1030 _.$UI.hasEvent = false; 1031 } 1032 } 1033 1034 if (_.windowW <= _.$breakpoints.tablet) { 1035 if (_.$UI.hasEvent && _.$UI.hasSidebar) _.toggleSidebar(); 1036 } 1037 }; 1038 1039 // v1.0.0 - Add Calendar Event(s) 1040 EvoCalendar.prototype.addCalendarEvent = function(arr) { 1041 var _ = this; 1042 1043 function addEvent(data) { 1044 if(!data.id) {
1045 console.log("%c Event named: \""+data.name+"\" doesn't have a unique ID ", "color:white;font-weight:bold;background-color:#e21d1d;"); 1046 } 1047 1048 if (data.date instanceof Array) { 1049 for (var j=0; j < data.date.length; j++) { 1050 if(isDateValid(data.date[j])) { 1051 data.date[j] = _.formatDate(new Date(data.date[j]), _.options.format); 1052 } 1053 } 1054 } else { 1055 if(isDateValid(data.date)) { 1056 data.date = _.formatDate(new Date(data.date), _.options.format); 1057 } 1058 } 1059 1060 if (!_.options.calendarEvents) _.options.calendarEvents = []; 1061 _.options.calendarEvents.push(data); 1062 // add to date's indicator 1063 _.addEventIndicator(data); 1064 // add to event list IF active.event_date === data.date 1065 if (_.$active.event_date === data.date) _.addEventList(data); 1066 // _.$elements.innerEl.find("[data-date-val='" + data.date + "']") 1067 1068 function isDateValid(date) { 1069 if(_.isValidDate(date)) { 1070 return true; 1071 } else { 1072 console.log("%c Event named: \""+data.name+"\" has invalid date ", "color:white;font-weight:bold;background-color:#e21d1d;"); 1073 } 1074 return false; 1075 } 1076 } 1077 if (arr instanceof Array) { // Arrays of events 1078 for(var i=0; i < arr.length; i++) { 1079 addEvent(arr[i]) 1080 } 1081 } else if (typeof arr === 'object') { // Single event 1082 addEvent(arr) 1083 } 1084 }; 1085 1086 // v1.0.0 - Remove Calendar Event(s) 1087 EvoCalendar.prototype.removeCalendarEvent = function(arr) { 1088 var _ = this; 1089 1090 function deleteEvent(data) { 1091 // Array index 1092 var index = _.options.calendarEvents.map(function (event) { return event.id }).indexOf(data); 1093 1094 if (index >= 0) { 1095 var event = _.options.calendarEvents[index]; 1096 // Remove event from calendar events 1097 _.options.calendarEvents.splice(index, 1); 1098 // remove to event list 1099 _.removeEventList(data); 1100 // remove event indicator 1101 _.removeEventIndicator(event); 1102 } else { 1103 console.log("%c "+data+": ID not found ", "color:white;font-weight:bold;background-color:#e21d1d;"); 1104 } 1105 } 1106 if (arr instanceof Array) { // Arrays of index 1107 for(var i=0; i < arr.length; i++) { 1108 deleteEvent(arr[i]) 1109 } 1110 } else { // Single index 1111 deleteEvent(arr) 1112 } 1113 }; 1114 1115 // v1.0.0 - Check if date is valid 1116 EvoCalendar.prototype.isValidDate = function(d){ 1117 return new Date(d) && !isNaN(new Date(d).getTime()); 1118 } 1119 1120 $.fn.evoCalendar = function() { 1121 var _ = this, 1122 opt = arguments[0], 1123 args = Array.prototype.slice.call(arguments, 1), 1124 l = _.length, 1125 i, 1126 ret; 1127 for (i = 0; i < l; i++) { 1128 if (typeof opt == 'object' || typeof opt == 'undefined') 1129 _[i].evoCalendar = new EvoCalendar(_[i], opt); 1130 else 1131 ret = _[i].evoCalendar[opt].apply(_[i].evoCalendar, args); 1132 if (typeof ret != 'undefined') return ret; 1133 } 1134 return _; 1135 }; 1136 1137}));
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.