/* global googleCalendarApiKey:true */
/**
* Component Fullcalendar
* @module Fullcalendar
* @param {jQuery} $ Instance of jQuery
* @return {Object} List of archive methods
*/
XA.component.calendar = (function($) {
/**
* This class is used by [Fullcalendar]{@link module:Fullcalendar} module for
* storing events option
* @class GetEvents
* @memberOf module:Fullcalendar
* @param {string} selector selector of event element
* @param {Object} options options of component
*/
function GetEvents(selector, options) {
this.data = options.data;
this.selector = selector;
this.options = options;
this.events = [];
this.checkSource();
}
/**
* checkSource method calls ["getJson"]{@link module:Fullcalendar.GetEvents.getJson}
* if "options.dataType" equal "json"
* and creates instance of
* ["InitCalendar"]{@link module:Fullcalendar.InitCalendar} class
* @name checkSource
* @function
* @memberOf module:Fullcalendar.GetEvents
*/
GetEvents.prototype.checkSource = function() {
var inst = this;
switch (inst.options.dataType) {
case "json":
inst.getJson();
new InitCalendar(inst.selector, inst.options, inst.events);
break;
case "gcalendar":
new InitCalendar(inst.selector, inst.options, inst.events);
break;
}
};
/**
* getJson method fills array of events with
* new event
* @name getJson
* @function
* @memberOf module:Fullcalendar.GetEvents
*/
GetEvents.prototype.getJson = function() {
var inst = this,
date,
dateEnd,
allDay = false,
tempObj = [];
$.each(inst.data, function() {
date = new Date(this.eventStart);
dateEnd = new Date(this.eventEnd);
if (date === dateEnd) {
allDay = true;
}
tempObj = {
title: this.eventName,
start: date,
end: dateEnd,
eventDescription: this.eventDescription,
eventLink: this.eventLink,
eventClass: this.eventClass
};
inst.events.push(tempObj);
});
};
/**
* This class is used by
* [GetEvents]{@link module:Fullcalendar.GetEvents} module and
* initializes instances of calendar with predefined list of options
* @class InitCalendar
* @memberOf module:Fullcalendar
* @param {string} selector DOM Root element of
* @param {Object} options options of component
* @param {Array} events options of event calendar ["event object"]{@link https://fullcalendar.io/docs/event-object}
*/
function InitCalendar(selector, options, events) {
var inst = this,
prevNext = "",
title = "",
calendarTypes = "";
if (options.dataType === "gcalendar") {
googleCalendarApiKey = options.calendarApiKey;
events = options.calendarId;
} else {
googleCalendarApiKey = null;
}
options.showPrevNext ? (prevNext = "prev, next") : "";
options.showMonthCaptions ? (title = "title") : "";
for (var i in options.calendarTypes) {
if (options.calendarTypes[i] === "day") {
options.calendarTypes[i] = "basicDay";
} else if (options.calendarTypes[i] === "week") {
options.calendarTypes[i] = "basicWeek";
}
}
if (options.calendarTypes.length > 1) {
calendarTypes = options.calendarTypes.join();
}
$(selector).fullCalendar({
monthNames: options.localization.monthNames,
monthNamesShort: options.localization.monthNamesShort,
dayNames: options.localization.dayNames,
dayNamesShort: options.localization.dayNamesShort,
nextDayThreshold: "00:00",
buttonText: {
agendaDay: "agenda day",
agendaWeek: "agenda week"
},
header: {
left: prevNext,
center: title,
right: calendarTypes
},
googleCalendarApiKey: googleCalendarApiKey,
events: events,
renderEvent: false,
eventRender: function(event, element) {
if (options.compactView && options.dataType === "json") {
$(element).css("display", "none");
} else {
if (options.dataType === "json") {
inst.attachTooltip(event, element, false);
}
}
element.addClass(event.eventClass);
},
eventAfterAllRender: function() {
if (options.compactView && options.dataType === "json") {
inst.renderCompactCalendarEvents(selector, events);
}
}
});
}
/**
* attachTooltip method creates, positions, and
* animates tooltips for events.
* @method
* @alias attachTooltip
* @memberOf module:Fullcalendar.InitCalendar
* @param {Object} event options of event calendar ["event object"]{@link https://fullcalendar.io/docs/event-object}
* @param {DOMElement} element DOM element of an event
* @param {boolean} compactCalendar is calendar in compact mode
*/
InitCalendar.prototype.attachTooltip = function(
event,
element,
compactCalendar
) {
var $tooltip, tooltipContent;
$(element).on("mouseenter", function() {
tooltipContent = "";
$(".calendar-tooltip").fadeOut();
$(".calendar-tooltip").remove();
if (compactCalendar) {
tooltipContent = "";
$.each(event, function() {
tooltipContent +=
"<div class='compact-event'>" +
"<span class='title'>" +
this.title +
"</span>" +
"<span class='description'>" +
this.eventDescription +
"</span>" +
"<span class='link'><a href='" +
this.eventLink +
"'>Link</a></span></div>";
});
} else {
tooltipContent =
"<span class='description'>" +
event.eventDescription +
"</span>" +
"<span class='link'>" +
event.eventLink +
"</span>";
}
$tooltip = $(
"<div style='border-radius:5px;border:1px solid #000;position:absolute;z-index:999; paading:5px;background:#FFF' class='calendar-tooltip'><div class='arrow'>" +
"</div><div class='events'>" +
tooltipContent +
"</div></div>"
);
$tooltip.css({
left: $(this).offset().left
});
$tooltip.css({
top: $(this).offset().top - $(this).height()
});
$("body").append($tooltip);
var timeout;
$(this).unbind("mouseleave");
$(this).on("mouseleave", function() {
timeout = setTimeout(function() {
$tooltip.fadeOut(function() {
$(this).remove();
});
}, 300);
$tooltip.unbind("mouseenter");
$tooltip.on("mouseenter", function() {
clearTimeout(timeout);
});
});
$tooltip.unbind("mouseleave");
$tooltip.on("mouseleave", function() {
$(this).fadeOut(function() {
$(this).remove();
});
});
});
};
/**
* attaches events for single days - compact calendar
* @method
* @alias renderCompactCalendarEvents
* @memberOf module:Fullcalendar.InitCalendar
* @param {Array} events ["event object"]{@link https://fullcalendar.io/docs/event-object}
* @param {string} selector selector of an event in DOM
*/
InitCalendar.prototype.renderCompactCalendarEvents = function(
selector,
events
) {
var inst = this,
currentDay,
currentDate,
currentEvent,
dc,
mc,
yc,
d,
m,
y,
de,
me,
ye,
he,
startDate,
endDate,
dayEvents = [];
$(selector)
.find(".fc-day")
.each(function() {
currentDay = this;
currentDate = new Date($(this).data("date"));
dc = currentDate.getDate();
mc = currentDate.getMonth();
yc = currentDate.getFullYear();
dayEvents = [];
$.each(events, function() {
currentEvent = this;
startDate = new Date(this.start);
d = startDate.getDate();
m = startDate.getMonth();
y = startDate.getFullYear();
if (this.end) {
endDate = new Date(this.end);
de = endDate.getDate();
me = endDate.getMonth();
ye = endDate.getFullYear();
he = endDate.getHours();
}
if (
yc >= y &&
yc <= ye &&
mc >= m &&
mc <= me &&
dc >= d &&
dc <= de
) {
if (yc == ye && mc == me && dc == de && he < 9) {
// If last day and hour < 9 do nothing
} else {
$(currentDay).addClass("selected-day");
dayEvents.push(currentEvent);
}
}
});
if (dayEvents.length) {
inst.attachTooltip(dayEvents, currentDay, true);
}
});
};
/**
* resizeCalendar method runs render of a calendar
* @memberOf module:Fullcalendar
* @param {string} selector Selector of a calendar component
* @private
*/
function resizeCalendar(selector) {
$(selector).fullCalendar("render");
}
/**
* This object stores all public api methods
* @type {Object.<Methods>}
* @memberOf module:Fullcalendar
* */
var api = {};
/**
* initInstance method creates instance of
* ["GetEvents"]{@link module:Fullcalendar.GetEvents} class and bind
* ["resizeCalendar"]{@link module:Fullcalendar.resizeCalendar} to window resize
* event
* @memberOf module:Fullcalendar
* @alias module:Fullcalendar.initInstance
*/
api.initInstance = function(component, prop) {
var selector = "#" + component.find(".event-calendar-inner").attr("id");
if (prop.compactView && prop.dataType === "json") {
$(this).addClass("compact-mode");
}
new GetEvents(selector, prop);
$(window).resize(function() {
resizeCalendar(selector);
});
};
/**
* init method calls in a loop for each
* full calendar component on a page and run Full calendar's
* ["initInstance"]{@link module:Fullcalendar.api.initInstance} method
* @memberOf module:Fullcalendar
* @alias module:Fullcalendar.init
*/
api.init = function() {
$(".event-calendar:not(.initialized)").each(function() {
var properties = $(this).data("properties");
api.initInstance($(this), properties);
$(this).addClass("initialized");
});
};
return api;
})(jQuery, document);
XA.register("calendar", XA.component.calendar);