const TIME_FORMAT = 'HH:mm'; const FLYING_TEAM_LABEL = 'Flying Team'; const FLYING_TEAM_BORDER_COLOR = "orange"; var overlaps = (function () { function getPositions(elem) { var pos, width, height; pos = $(elem).position(); width = $(elem).width(); height = $(elem).height(); return [[pos.left, pos.left + width], [pos.top, pos.top + height]]; } function comparePositions(p1, p2) { var r1, r2; r1 = p1[0] < p2[0] ? p1 : p2; r2 = p1[0] < p2[0] ? p2 : p1; return r1[1] > r2[0] || r1[0] === r2[0]; } return function (x, y, element) { var pos1 = [[x, x + 100], [y, y + 20]], pos2 = getPositions(element); console.log(x, y, element); return comparePositions(pos1[0], pos2[0]) && comparePositions(pos1[1], pos2[1]); }; })(); var eventsCleared = []; function add_event(event, color, subjectId, boxBody) { var eventElement = $('<div class="fc-event ui-draggable ui-draggable-handle hidden-print">' + event.title + '<span style="float:right;padding-right:5px;">' + event.duration + '</span></div>' ) ; eventElement.removeData(); var constraintStart = $.fullCalendar.moment(event.appointment_start); var borderColor; var location = event.location; if (location === FLYING_TEAM_LABEL) { eventElement.css('border', '2px solid ' + FLYING_TEAM_BORDER_COLOR); location = event.flying_team_location + ' (FT)'; borderColor = FLYING_TEAM_BORDER_COLOR; } var event_title = event.short_title; if (event_title === undefined || event_title === "") { event_title = event.title; } eventElement.data('event', { appointment_start: event.appointment_start, appointment_end: event.appointment_end, title: event_title, stick: true, color: color + " !important", duration: event.duration, original_duration: event.duration, subject: event.subject, subject_id: subjectId, id: event.id, link_id: event.link_id, link_who: event.link_who, link_when: event.link_when, location: event.location, flying_team_location: event.flying_team_location, constraint: { start: constraintStart, end: $.fullCalendar.moment(event.appointment_end) }, borderColor: borderColor }); eventElement.draggable({ zIndex: 999, revert: true, revertDuration: 0, start: function (event, ui) { $(this).popover('disable'); } }); eventElement.css('background-color', color); eventElement.css('width', event.width); boxBody.append(eventElement); eventElement.popover({ container: 'body', trigger: 'click', content: location + ', appointment starts at ' + constraintStart.format(TIME_FORMAT) }); } function get_subjects_events(day) { $.get('/api/events/' + day, function (data) { $("#subjects").empty(); var availabilities = data.availabilities; $.each(availabilities, function (index, event) { event.backgroundColor = '#AAFFAA !important'; event.start = $.fullCalendar.moment(event.link_when); event.end = $.fullCalendar.moment(event.link_end); event.rendering = 'background'; event.resourceId = event.link_who.toString(); event.className = 'background-event'; $('#calendar').fullCalendar('renderEvent', event, true); }); var holidays = data.holidays; $.each(holidays, function (index, event) { event.backgroundColor = '#FFAAAA !important'; event.start = $.fullCalendar.moment(event.link_when); event.end = $.fullCalendar.moment(event.link_end); event.rendering = 'background'; event.resourceId = event.link_who.toString(); event.className = 'background-event'; $('#calendar').fullCalendar('renderEvent', event, true); }); var subjects = data.data; $.each(subjects, function (index, subject) { var divSubject = $("<div class='col-md-4 col-lg-3 col-sm-12 subjects-events'/>"); var boxSubject = $("<div class='box box-primary'/>").css('border-top-color', subject.color); var boxBody = $("<div class='box-body' id='subject_" + subject.id + "'>"); var boxHeader = $("<div class='box-header with-border'/>"); var title_subject = $("<h4>" + subject.name + "( " + subject.start + ") <span style='float:right;padding-right:5px;'>" + subject.location + "</span></h4>"); boxHeader.append(title_subject); $.each(subject.events, function (index_event, event) { if (event.link_when) { event.title = event.short_title; event.color = subject.color + ' !important'; event.start = $.fullCalendar.moment(event.link_when); event.end = $.fullCalendar.moment(event.link_end); event.resourceId = event.link_who.toString(); event.subject_id = subject.id; event.original_duration = event.duration; event.constraint = { start: $.fullCalendar.moment(event.appointment_start), end: $.fullCalendar.moment(event.appointment_end) }; $('#calendar').fullCalendar('renderEvent', event, true); } else { add_event(event, subject.color, subject.id, boxBody); } }); boxSubject.append(boxHeader); boxSubject.append(boxBody); divSubject.append(boxSubject); $("#subjects").append(divSubject); divSubject.droppable({ drop: function (event, ui) { } }); }); }); } function remove_event(event) { $('#calendar').fullCalendar('removeEvents', event.id); var selector = '#subject_' + event.subject_id; var boxBody = $(selector); event.duration = event.original_duration; event.removed = true; //remove !important event.color = event.color.substring(0, 7); eventsCleared.push(event.link_id); add_event(event, event.color, event.subject_id, boxBody); } $(document).ready(function () { $('#calendar').fullCalendar({ schedulerLicenseKey: 'CC-Attribution-NonCommercial-NoDerivatives', defaultView: 'agendaDay', eventDurationEditable: false, eventStartEditable: true, editable: true, selectable: true, eventOverlap: function (stillEvent, movingEvent) { if (stillEvent.rendering === "background") { return true; } return false; }, weekends: false, scrollTime: '08:00', slotDuration: '00:30', snapDuration: '00:05', displayEventTime: true, resourceOrder: 'role', resourceGroupField: 'role', dragRevertDuration: 0, minTime: "08:00:00", maxTime: "19:00:00", groupByResource: true, height: "auto", customButtons: { save: { text: 'Save', click: function () { calendarEvents = $('#calendar').fullCalendar('clientEvents'); eventsToPersist = []; var saveButton = $(".fc-save-button"); var currentBorder = saveButton.css('border-color'); $.each(calendarEvents, function (i, calendar_event) { if (calendar_event.rendering !== "background") { eventsToPersist.push({ 'link_id': calendar_event.link_id, 'link_who': parseInt(calendar_event.resourceId), 'start': calendar_event.start.format() }); var index = eventsCleared.indexOf(calendar_event.link_id); if (index > -1) { eventsCleared.splice(index, 1); } } }); $.post({ url: events_url, data: { events_to_persist: JSON.stringify(eventsToPersist), events_to_clear: JSON.stringify(eventsCleared) }, dataType: "json" }).done(function (data) { saveButton.css('border-color', 'green'); setTimeout(function () { saveButton.css('border-color', currentBorder); }, 200); }).error(function (data) { console.log(data); saveButton.css('border-color', 'red'); showErrorInfo("There was an unexpected problem with saving data. " + "Please contact administrators."); setTimeout(function () { saveButton.delay(200).css('border-color', currentBorder); }, 200); }); } }, clear: { text: 'Clear', click: function () { calendarEvents = $('#calendar').fullCalendar('clientEvents'); $.each(calendarEvents, function (i, calendar_event) { remove_event(calendar_event); }); } }, toPdf: { text: 'PDF', click: function () { return html2canvas(document.getElementById("calendar")).then(function (canvas) { var container = document.createElement("div"); container.style.backgroundColor = "#FFFFFF"; container.appendChild(canvas); document.body.appendChild(container); var pdf = new jsPDF('l', 'mm', [297, 210]); pdf.addHTML(container, function () { pdf.save('daily-planning.pdf'); document.body.removeChild(container); }); }); } } }, viewRender: function (view, element) { var date = view.start.format('YYYY-MM-DD'); $('#calendar').fullCalendar('removeEvents'); get_subjects_events(date); }, businessHours: { start: '08:00', end: '19:00' }, header: { left: 'prev,next today', center: 'title', right: 'save, clear, toPdf' }, droppable: true, resourceAreaWidth: '15%', resourceLabelText: 'Workers', resources: resources_url, events: [], eventRender: function (event, element) { if (event.rendering !== 'background') { element.popover({ title: event.short_title, container: 'body', placement: 'bottom', trigger: 'click', content: '<ul>' + '<li>' + event.subject + '</li>' + '<li>' + event.start.format(TIME_FORMAT) + ' - ' + event.end.format(TIME_FORMAT) + '</li>' + '<li>Appointment starts: ' + event.constraint.start.format(TIME_FORMAT) + '</li>' + '<li>Location: ' + (event.location !== FLYING_TEAM_LABEL ? event.location : event.flying_team_location + ' (FT)') + '</li>' + '</ul>', html: true }); } else { } }, selectAllow: function (selectInfo) { return false; }, eventDragStop: function (event, jsEvent, ui, view) { // var x = isElemOverDiv(jsEvent.clientX, jsEvent.clientY, $('#subjects')); $('.popover').popover('hide'); var x = overlaps(jsEvent.clientX, jsEvent.clientY, $('#subjects')); if (x) { remove_event(event); } }, eventDragStart: function (event, jsEvent, view) { $('.popover').popover('hide'); }, selectHelper: true, drop: function (date, jsEvent, ui, resourceId) { $(this).remove(); } }); }) ;