Finish migration

parent e72c1da9
...@@ -87,6 +87,9 @@ class EventCalenderJSSerializer(CalenderJSSerializer): ...@@ -87,6 +87,9 @@ class EventCalenderJSSerializer(CalenderJSSerializer):
pass pass
return "#616161" return "#616161"
def _text_color(self, instance):
return "#FFFFFF"
class UnpublishedEventSerializer(CalenderJSSerializer): class UnpublishedEventSerializer(CalenderJSSerializer):
""" """
......
...@@ -81,14 +81,15 @@ ...@@ -81,14 +81,15 @@
border-radius: 0; border-radius: 0;
border: none; border: none;
overflow: hidden; overflow: hidden;
transition-property: opacity;
.fc-content { .fc-content {
padding: 5px; padding: 5px;
transition: opacity 300ms ease-in-out 0s; transition: all 300ms ease-in-out 0s;
-moz-transition: opacity 300ms ease-in-out 0s; -moz-transition: all 300ms ease-in-out 0s;
-webkit-transition: opacity 300ms ease-in-out 0s; -webkit-transition: all 300ms ease-in-out 0s;
-o-transition: opacity 300ms ease-in-out 0s; -o-transition: all 300ms ease-in-out 0s;
} }
.fc-bg { .fc-bg {
......
var FC = $.fullCalendar; // a reference to FullCalendar's root namespace
var View = FC.View; // the class that all views must inherit from
var ListView; // our subclass
ListView = View.extend({
title: gettext("Upcoming Events"),
initialize: function () {
this.title = gettext("Upcoming Events");
}
computeTitle: function (d) {
return this.title;
},
fetchInitialEvents: function (dateProfile) {
var calendar = this.calendar;
var today = new Date();
return calendar.requestEvents(
calendar.msToMoment(Date.UTC(today.getFullYear(), today.getMonth(), today.getDate(), 0, 0, 0), false),
calendar.msToMoment(Date.UTC(today.getFullYear() + 2, today.getMonth(), today.getDate(), 0, 0, 0), false)
);
},
renderEvents: function (events) {
var root = $("<div>").addClass("accordion bordered");
events.sort(function (a, b) {
return a.start < b.start ? -1 : a.start > b.start ? 1 : 0;
});
if (events.length === 0) {
this.el.html('<div class="alert alert-info">' + gettext('No events planned in the selected period.') +'</div>');
}
for (var i = 0; i < events.length; i++) {
var e = events[i];
if (e.is_birthday) {
break;
}
var date = e.start.format('LLLL');
var eventCard = $("<div>").addClass("card mb-0");
var eventIndicator = $("<div>")
.addClass("event-indication")
.attr("style", "background-color: " + e.backgroundColor);
var cardHead = $("<div>").addClass("card-header collapsed")
.attr("data-toggle", "collapse")
.attr("data-target", "#event-content-" + i);
cardHead.append(eventIndicator);
cardHead.append("<div class=\"title\">" + e.title + " " +
"(<span class=\"date\">" + date + "</span>)</div>");
var cardContent = $("<div>")
.addClass("collapse")
.attr("id", "event-content-" + i);
var url = $("<a>")
.addClass("btn btn-primary")
.attr("href", e.url)
.attr("target", e.blank ? "_blank" : "_self")
.html(gettext("Go to event"));
var cardBody = $("<div>")
.addClass("card-body")
.html("<p>" + e.description + "</p>");
cardBody.append(url);
cardContent.append(cardBody);
eventCard.append(cardHead);
eventCard.append(cardContent);
root.append(eventCard);
this.el.html(root);
}
},
});
FC.views.list = ListView; // register our class with the view system
class ListView extends FullCalendar.View { class ListView extends FullCalendar.View {
renderSkeleton() {
// responsible for displaying the skeleton of the view within the already-defined
// this.el, an HTML element
console.log(this);
}
unrenderSkeleton() {
// should undo what renderSkeleton did
}
renderDates(dateProfile) {
// responsible for rendering the given dates
}
unrenderDates() {
// should undo whatever renderDates does
}
renderEvents(eventStore, eventUiHash) { renderEvents(eventStore, eventUiHash) {
const events = Object.values(eventStore.instances); const skeleton = document.createElement('div');
skeleton.id = 'fc-listview';
skeleton.classList.add('accordion', 'bordered');
var root = $("<div>").addClass("accordion bordered"); const locale = this.dateEnv.locale.codeArg;
const events = Object.values(eventStore.instances);
events.sort(function (a, b) { events.sort(function (a, b) {
return a.range.start < b.range.start ? -1 : return a.range.start < b.range.start ? -1 :
...@@ -31,70 +16,88 @@ class ListView extends FullCalendar.View { ...@@ -31,70 +16,88 @@ class ListView extends FullCalendar.View {
var alertEl = document.createElement('div'); var alertEl = document.createElement('div');
alertEl.id = 'fc-no-events'; alertEl.id = 'fc-no-events';
alertEl.classList.add('alert', 'alert-info'); alertEl.classList.add('alert', 'alert-info');
var text = document.createTextNode(gettext('No events planned in the selected period.')); alertEl.append(gettext('No events planned in the selected period.'));
alertEl.appendChild(text); this.el.append(alertEl);
this.el.appendChild(alertEl);
} }
for (let i = 0; i < events.length; i++) { for (let i = 0; i < events.length; i++) {
const instance = events[i]; const instance = events[i];
const def = eventStore.defs[instance.defId]; const def = eventStore.defs[instance.defId];
console.log(instance, def);
console.log(def.extendedProps);
if (def.extendedProps.isBirthday) { if (def.extendedProps.isBirthday) {
break; break;
} }
// var date = def.range.start.toLocaleString(); var date = instance.range.start.toLocaleDateString(locale, {
// console.log(def.range.start); hour: '2-digit',
minute: '2-digit',
// var eventCard = $("<div>").addClass("card mb-0"); day: 'numeric',
// month: 'long',
// var eventIndicator = $("<div>") weekday: 'long',
// .addClass("event-indication") year: 'numeric',
// .attr("style", "background-color: " + e.backgroundColor); hour12: false,
// var cardHead = $("<div>").addClass("card-header collapsed") });
// .attr("data-toggle", "collapse")
// .attr("data-target", "#event-content-" + i); const eventCard = document.createElement('div');
// eventCard.classList.add('card', 'mb-0');
// cardHead.append(eventIndicator);
// cardHead.append("<div class=\"title\">" + e.title + " " + const eventIndicator = document.createElement('div');
// "(<span class=\"date\">" + date + "</span>)</div>"); eventIndicator.classList.add('event-indication');
// eventIndicator.style = 'background-color: ' + def.ui.backgroundColor;
// var cardContent = $("<div>")
// .addClass("collapse") const cardHead = document.createElement('div');
// .attr("id", "event-content-" + i); cardHead.classList.add('card-header', 'collapsed');
// cardHead.dataset.toggle = 'collapse';
// var url = $("<a>") cardHead.dataset.target = '#event-content-' + i;
// .addClass("btn btn-primary")
// .attr("href", e.url) const cardTitle = document.createElement('div');
// .attr("target", e.blank ? "_blank" : "_self") cardTitle.classList.add('title');
// .html(gettext("Go to event")); const cardDate = document.createElement('span');
// cardDate.append(date);
// var cardBody = $("<div>") cardTitle.append(def.title + ' (');
// .addClass("card-body") cardTitle.append(cardDate);
// .html("<p>" + e.description + "</p>"); cardTitle.append(')');
// cardBody.append(url);
// cardHead.append(eventIndicator);
// cardContent.append(cardBody); cardHead.append(cardTitle);
// eventCard.append(cardHead);
// eventCard.append(cardContent); const cardContent = document.createElement('div');
// cardContent.classList.add('collapse');
// root.append(eventCard); cardContent.id = 'event-content-' + i;
// this.el.appendChild(root);
const url = document.createElement('a');
url.classList.add('btn', 'btn-primary');
url.href = def.url;
url.target = def.extendedProps.blank ? '_blank' : '_self';
url.append(gettext("Go to event"));
const cardBody = document.createElement('div');
cardBody.classList.add('card-body');
const cardBodyText = document.createElement('p');
cardBodyText.append(def.extendedProps.description);
cardBody.append(cardBodyText);
cardBody.append(url);
cardContent.append(cardBody);
eventCard.append(cardHead);
eventCard.append(cardContent);
skeleton.append(eventCard);
} }
this.el.append(skeleton);
} }
unrenderEvents() { unrenderEvents() {
const noEventsEl = document.getElementById('fc-no-events'); const noEventsEl = this.el.querySelector('#fc-no-events');
if (noEventsEl) { if (noEventsEl) {
noEventsEl.remove(); noEventsEl.remove();
} }
// should undo whatever renderEvents does
}
const listView = this.el.querySelector('#fc-listview');
if (listView) {
listView.remove();
}
}
} }
const listViewPlugin = FullCalendar.createPlugin({ const listViewPlugin = FullCalendar.createPlugin({
......
var BIRTHDAYS_COOKIE = 'showbirthdays'; const BIRTHDAYS_COOKIE = 'showbirthdays';
var VIEW_COOKIE = 'agendaview'; const VIEW_COOKIE = 'calendarview';
var SOURCES = { const SOURCES = {
events: "/api/v1/events/calendarjs", events: {
birthdays: "/api/v1/members/birthdays", id: 'event',
partners: "/api/v1/partners/calendarjs", url: '/api/v1/events/calendarjs/',
unpublishedEvents: "/api/v1/events/unpublished" },
birthdays: {
id: 'birthdays',
url: '/api/v1/members/birthdays/',
},
partners: {
id: 'partners',
url: '/api/v1/partners/calendarjs/',
},
unpublished: {
id: 'unpublished',
url: '/api/v1/events/unpublished/',
},
}; };
function checkResponsiveState(calendarElement, windowWidth, view) { function checkResponsiveState(calendar, windowWidth, view) {
var buttonText = gettext('show birthdays'); var buttonText = gettext('show birthdays');
calendarElement.fullCalendar('removeEventSource', SOURCES.birthdays); if (calendar.getEventSourceById(SOURCES.birthdays.id)) {
calendar.getEventSourceById(SOURCES.birthdays.id).remove();
}
if (windowWidth <= 768) { if (windowWidth <= 768) {
calendarElement.fullCalendar('option', 'header', { calendar.setOption('header', {
right: '' right: ''
}); });
} else { } else {
if (view.name === 'list') { if (view.type === 'list') {
calendarElement.fullCalendar('option', 'header', { calendar.setOption('header', {
right: 'list,agendaWeek,month' right: 'list,timeGridWeek,dayGridMonth'
}); });
} else { } else {
if (Cookies.get(BIRTHDAYS_COOKIE)) { if (Cookies.get(BIRTHDAYS_COOKIE)) {
calendarElement.fullCalendar('addEventSource', SOURCES.birthdays); calendar.addEventSource(SOURCES.birthdays);
buttonText = gettext('hide birthdays'); buttonText = gettext('hide birthdays');
} }
calendarElement.fullCalendar('option', 'header', { calendar.setOption('header', {
right: 'showBirthdays, list,agendaWeek,month prev,next today' right: 'showBirthdays, list,timeGridWeek,dayGridMonth prev,next today'
}); });
} }
} }
$('.fc-showBirthdays-button').html(buttonText); $('.fc-showBirthdays-button').html(buttonText);
} }
$(function () { document.addEventListener('DOMContentLoaded', function () {
var calendarElement = $('#calendar'); const calendarEl = document.getElementById('calendar');
var showUnpublished = calendarElement.data('show-unpublished'); const showUnpublished = calendarEl.dataset['show-unpublished'];
var defaultDate = calendarElement.data('default-date'); let defaultDate = calendarEl.dataset['default-date'];
var isAuthenticated = calendarElement.data('authenticated'); const isAuthenticated = calendarEl.dataset.authenticated;
var language = calendarElement.data('language'); const language = calendarEl.dataset.language;
var eventSources = [SOURCES.events, SOURCES.partners]; const eventSources = [SOURCES.events, SOURCES.partners];
if (showUnpublished) { if (showUnpublished) {
eventSources.push(SOURCES.unpublishedEvents); eventSources.push(SOURCES.unpublished);
} }
if (Cookies.get(BIRTHDAYS_COOKIE)) { if (Cookies.get(BIRTHDAYS_COOKIE)) {
eventSources.push(SOURCES.birthdays); eventSources.push(SOURCES.birthdays);
} }
var tmpView = ($(window).width() < 979) ? 'list' : 'agendaWeek'; let tmpView = window.innerWidth < 979 ? 'list' : 'timeGridWeek';
if (Cookies.get(VIEW_COOKIE) !== undefined) { if (Cookies.get(VIEW_COOKIE) !== undefined) {
tmpView = Cookies.get(VIEW_COOKIE); tmpView = Cookies.get(VIEW_COOKIE);
} }
// History idea and code parts from if (window.location.hash.indexOf('date') > -1) {
// https://github.com/fullcalendar/fullcalendar/issues/659#issuecomment-132535804 defaultDate = window.location.hash.substr(window.location.hash.indexOf('date') + 5, 24);
// and https://github.com/fullcalendar/fullcalendar/issues/659#issuecomment-245544401
var startDate = new Date(defaultDate);
var tmpYear = startDate.getFullYear();
var tmpMonth = startDate.getMonth();
var tmpDay = startDate.getDate();
var vars = window.location.hash.split("&");
for (var i = 0; i < vars.length; i++) {
if (vars[i].match("^#year")) tmpYear = vars[i].substring(6);
if (vars[i].match("^month")) tmpMonth = vars[i].substring(6) - 1;
if (vars[i].match("^day")) tmpDay = vars[i].substring(4);
if (vars[i].match("^view")) tmpView = vars[i].substring(5);
} }
calendarElement.fullCalendar({ const calendar = new FullCalendar.Calendar(calendarEl, {
plugins: ['timeGrid', 'dayGrid', 'bootstrap', listViewPlugin],
aspectRatio: 1.8, aspectRatio: 1.8,
theme: 'bootstrap4', themeSystem: 'bootstrap',
eventSources: eventSources,
defaultView: tmpView, defaultView: tmpView,
defaultDate: defaultDate,
eventSources: eventSources,
firstDay: 1, firstDay: 1,
scrollTime: '14:00:00', scrollTime: '14:00:00',
timeFormat: 'HH:mm', eventTimeFormat: {
hour: '2-digit',
minute: '2-digit',
hour12: false,
},
eventLimit: true, eventLimit: true,
locale: language, locale: language,
nowIndicator: true,
views: { views: {
list: { list: {
buttonText: gettext('list'), buttonText: gettext('list'),
duration: {years: 5} duration: { years: 5 },
type: 'list',
titleFormat: function() { return gettext("Upcoming Events") },
} }
}, },
defaultDate: defaultDate,
customButtons: customButtons:
isAuthenticated ? { isAuthenticated ? {
showBirthdays: { showBirthdays: {
...@@ -92,71 +103,63 @@ $(function () { ...@@ -92,71 +103,63 @@ $(function () {
if (Cookies.get(BIRTHDAYS_COOKIE)) { if (Cookies.get(BIRTHDAYS_COOKIE)) {
e.target.innerHTML = gettext('show birthdays'); e.target.innerHTML = gettext('show birthdays');
Cookies.remove(BIRTHDAYS_COOKIE); Cookies.remove(BIRTHDAYS_COOKIE);
calendarElement.fullCalendar('removeEventSource', SOURCES.birthdays); calendar.getEventSourceById(SOURCES.birthdays.id).remove();
} else { } else {
e.target.innerHTML = gettext('hide birthdays'); e.target.innerHTML = gettext('hide birthdays');
Cookies.set(BIRTHDAYS_COOKIE, 1); Cookies.set(BIRTHDAYS_COOKIE, 1);
calendarElement.fullCalendar('addEventSource', SOURCES.birthdays); calendar.addEventSource(SOURCES.birthdays);
} }
} }
} }
} : {} } : {},
,
header: { header: {
right: 'showBirthdays, list,agendaWeek,month prev,next today' right: 'showBirthdays, list,timeGridWeek,dayGridMonth prev,next today'
}, },
eventClick: function (event) { eventClick: function ({ jsEvent, event }) {
if (event.url && event.blank) { console.log(event);
if (event.url && event.extendedProps.blank) {
jsEvent.preventDefault();
window.open(event.url, '_blank'); window.open(event.url, '_blank');
return false;
} else if (event.url) {
window.replace(event.url);
return false;
} }
}, },
eventRender: function (event, element) { eventRender: function ({ el, event }) {
element.attr('title', event.description); el.setAttribute(
'title', event.extendedProps.description);
}, },
viewRender: function (view) { viewSkeletonRender: function ({ view }) {
var prevView = Cookies.get(VIEW_COOKIE); const prevView = Cookies.get(VIEW_COOKIE);
var moment = calendarElement.fullCalendar('getDate');
if (moment && moment.isValid()) { const date = calendar.getDate();
window.location.hash = 'year=' + moment.format('YYYY') + '&month=' + (moment.format('M')) + '&day=' + moment.format('DD') + '&view=' + view.name; window.location.hash = 'date=' + date.toISOString() + '&view=' + view.type;
}
if (view.name !== prevView) { if (view.type !== prevView) {
var windowWidth = $(window).width(); const windowWidth = window.innerWidth;
Cookies.set(VIEW_COOKIE, view.name); Cookies.set(VIEW_COOKIE, view.type);
checkResponsiveState(calendarElement, windowWidth, view); checkResponsiveState(calendar, windowWidth, view);
} }
} },
, datesRender: function ({ view }) {
const date = calendar.getDate();
window.location.hash = 'date=' + date.toISOString() + '&view=' + view.type;
},
windowResize: function () { windowResize: function () {
var windowWidth = $(window).width(); const windowWidth = window.innerWidth;
var view = (windowWidth <= 768) ? 'list' : Cookies.get(VIEW_COOKIE); const view = (windowWidth <= 768) ? 'list' : Cookies.get(VIEW_COOKIE);
var currentView = $('#calendar').fullCalendar('getView'); const currentView = calendar.view;
if (view !== currentView.name) { if (view !== currentView.type) {
calendarElement.fullCalendar('changeView', view); calendar.changeView(view);
} else { } else {
checkResponsiveState(calendarElement, windowWidth, currentView); checkResponsiveState(calendar, windowWidth, currentView);
} }
}