summaryrefslogtreecommitdiff
path: root/addons/web/static/src
diff options
context:
space:
mode:
authorRomeo Fragomeli <rfr@odoo.com>2019-12-12 11:55:40 +0000
committerPierre Paridans <app@odoo.com>2020-03-31 15:06:11 +0000
commitebce7719b624136da2b26a73acf8930538c7a38c (patch)
treec89870d188705a37dee60e69aed2dd6e9eee524b /addons/web/static/src
parentd2851b203924dcb0e56e534751a552e99757971b (diff)
[REF] calendar,web: update to FullCalendar v4
This commit updates the FullCalendar library from v3 to v4. The purpose of this update for us is to add a proper support of the drag-and-drop of events on mobile. But also to fix scrolling issues present mainly on smaller screens. In those configurations multi/inner-scrolls were present resulting into either the inability to properly scroll the desired content or even blocking alltogether the scroll. As a nice-to-have feature, the version 4 removes its dependency on the jQuery library, allowing a faster loading of a bigger set of events. Last but not least, this version also reduces its dependency on the Moment.js library (but still keeps a binding to it for compatibility purpose). This commit focus only on the update of the library itself and the adaptation of the related code to keep it working. Further enhancements/fixes will be done later on. To do so it modifies the following points: * Update the library in itself (js, css...). * Convert all FullCalendar's method calls to the new syntax (e.g. `$calendar.fullCalendar('destroy')` becomes `calendar.destroy()`). * Add a utility method to convert v4 events into the old v3 event structure to ease the transition from one version to the other. * Wrap all event's custom fields into a new event's `extendedProps` object (as its the new way of storing them instead of directly as a prop. of the event). * Adapt `slotLabelFormat` and `weekNumberCalculation`. * Use the view's new names: ** `agendaDay` -> `timeGridDay` ** `agendaWeek` -> `timeGridWeek` ** `month` -> `dayGridMonth` * Use the option's new names: ** `viewRender` -> `datesRender` ** `eventMouseover` -> `eventMouseEnter` ** `eventMouseout` -> `eventMouseLeave` ** `isRTL` -> `dir` ** `selectHelper` -> `selectMirror` ** `weekNumberTitle` -> `weekLabel` Ref: https://fullcalendar.io/docs/upgrading-from-v3 Task ID: 2092550
Diffstat (limited to 'addons/web/static/src')
-rw-r--r--addons/web/static/src/js/views/calendar/calendar_model.js37
-rw-r--r--addons/web/static/src/js/views/calendar/calendar_popover.js4
-rw-r--r--addons/web/static/src/js/views/calendar/calendar_renderer.js262
-rw-r--r--addons/web/static/src/js/views/calendar/calendar_view.js16
-rw-r--r--addons/web/static/src/scss/web_calendar.scss20
5 files changed, 215 insertions, 124 deletions
diff --git a/addons/web/static/src/js/views/calendar/calendar_model.js b/addons/web/static/src/js/views/calendar/calendar_model.js
index 7ed57ceafa9..78fa6fdaf5e 100644
--- a/addons/web/static/src/js/views/calendar/calendar_model.js
+++ b/addons/web/static/src/js/views/calendar/calendar_model.js
@@ -356,7 +356,7 @@ return AbstractModel.extend({
return this._rpc({
model: this.modelName,
method: 'write',
- args: [[record.id], data],
+ args: [[parseInt(record.id, 10)], data],
context: context
});
},
@@ -419,11 +419,22 @@ return AbstractModel.extend({
* @returns {Object}
*/
_getFullCalendarOptions: function () {
+ var format12Hour = {
+ hour: 'numeric',
+ minute: '2-digit',
+ omitZeroMinute: true,
+ meridiem: 'short'
+ };
+ var format24Hour = {
+ hour: 'numeric',
+ minute: '2-digit',
+ hour12: false,
+ };
return {
- defaultView: (this.mode === "month")? "month" : ((this.mode === "week")? "agendaWeek" : ((this.mode === "day")? "agendaDay" : "agendaWeek")),
+ defaultView: (this.mode === "month")? "dayGridMonth" : ((this.mode === "week")? "timeGridWeek" : ((this.mode === "day")? "timeGridDay" : "timeGridWeek")),
header: false,
selectable: this.creatable && this.create_right,
- selectHelper: true,
+ selectMirror: true,
editable: this.editable,
droppable: true,
navLinks: false,
@@ -434,14 +445,18 @@ return AbstractModel.extend({
nowIndicator: true,
weekNumbers: true,
weekNumbersWithinDays: true,
- weekNumberTitle: _t("Week") + " ",
+ weekNumberCalculation: function (date) {
+ // Since FullCalendar v4 ISO 8601 week date is preferred so we force the old system
+ return moment(date).week();
+ },
+ weekLabel: _t("Week"),
allDayText: _t("All day"),
monthNames: moment.months(),
monthNamesShort: moment.monthsShort(),
dayNames: moment.weekdays(),
dayNamesShort: moment.weekdaysShort(),
firstDay: this.week_start,
- slotLabelFormat: _t.database.parameters.time_format.search("%H") != -1 ? 'H:mm': 'h(:mm)a',
+ slotLabelFormat: _t.database.parameters.time_format.search("%H") !== -1 ? format24Hour : format12Hour,
};
},
/**
@@ -733,10 +748,10 @@ return AbstractModel.extend({
}
var r = {
'record': evt,
- 'start': date_start,
- 'end': date_stop,
- 'r_start': date_start.clone(),
- 'r_end': date_stop.clone(),
+ 'start': date_start.local(true).toDate(),
+ 'end': date_stop.local(true).toDate(),
+ 'r_start': date_start.clone().local(true).toDate(),
+ 'r_end': date_stop.clone().local(true).toDate(),
'title': the_title,
'allDay': all_day,
'id': evt.id,
@@ -754,8 +769,8 @@ return AbstractModel.extend({
// allow to resize in month mode
r.reset_allday = r.allDay;
r.allDay = true;
- r.start = date_start.format('YYYY-MM-DD');
- r.end = date_stop.startOf('day').format('YYYY-MM-DD');
+ r.start = date_start.toDate();
+ r.end = date_stop.startOf('day').toDate();
r.showTime = true;
}
diff --git a/addons/web/static/src/js/views/calendar/calendar_popover.js b/addons/web/static/src/js/views/calendar/calendar_popover.js
index 9b4af4bb065..8bfadbc7c4d 100644
--- a/addons/web/static/src/js/views/calendar/calendar_popover.js
+++ b/addons/web/static/src/js/views/calendar/calendar_popover.js
@@ -112,7 +112,7 @@ var CalendarPopover = Widget.extend(WidgetAdapterMixin, StandaloneFieldManagerMi
var field = {
name: fieldName,
string: displayFieldInfo.attrs.string || fieldInfo.string,
- value: self.event.record[fieldName],
+ value: self.event.extendedProps.record[fieldName],
type: fieldInfo.type,
};
if (field.type === 'selection') {
@@ -199,7 +199,7 @@ var CalendarPopover = Widget.extend(WidgetAdapterMixin, StandaloneFieldManagerMi
ev.preventDefault();
this.trigger_up('edit_event', {
id: this.event.id,
- title: this.event.record.display_name,
+ title: this.event.extendedProps.record.display_name,
});
},
/**
diff --git a/addons/web/static/src/js/views/calendar/calendar_renderer.js b/addons/web/static/src/js/views/calendar/calendar_renderer.js
index 7f281e474c9..0ad1c4c0c6b 100644
--- a/addons/web/static/src/js/views/calendar/calendar_renderer.js
+++ b/addons/web/static/src/js/views/calendar/calendar_renderer.js
@@ -16,9 +16,9 @@ var _t = core._t;
var qweb = core.qweb;
var scales = {
- day: 'agendaDay',
- week: 'agendaWeek',
- month: 'month'
+ day: 'timeGridDay',
+ week: 'timeGridWeek',
+ month: 'dayGridMonth'
};
var SidebarFilterM2O = relational_fields.FieldMany2One.extend({
@@ -78,6 +78,7 @@ var SidebarFilter = Widget.extend(FieldManagerMixin, {
{
mode: 'edit',
attrs: {
+ string: _t(self.fields[self.fieldName].string),
placeholder: "+ " + _.str.sprintf(_t("Add %s"), self.title),
can_create: false
},
@@ -192,6 +193,7 @@ return AbstractRenderer.extend({
this.hideDate = params.hideDate;
this.hideTime = params.hideTime;
this.canDelete = params.canDelete;
+ this._isInDOM = false;
},
/**
* @override
@@ -209,22 +211,29 @@ return AbstractRenderer.extend({
* @override
*/
on_attach_callback: function () {
+ this._super(...arguments);
+ this._isInDOM = true;
if (config.device.isMobile) {
this.$el.height($(window).height() - this.$el.offset().top);
}
- var scrollTop = this.$calendar.find('.fc-scroller').scrollTop();
- if (scrollTop) {
- this.$calendar.fullCalendar('reinitView');
- } else {
- this.$calendar.fullCalendar('render');
- }
+ // BUG Test ????
+ // this.$el.height($(window).height() - this.$el.offset().top);
+ this.calendar.render();
+ this._renderCalendar();
+ },
+ /**
+ * Called when the field is detached from the DOM.
+ */
+ on_detach_callback: function () {
+ this._super(...arguments);
+ this._isInDOM = false;
},
/**
* @override
*/
destroy: function () {
- if (this.$calendar) {
- this.$calendar.fullCalendar('destroy');
+ if (this.calendar) {
+ this.calendar.destroy();
}
if (this.$small_calendar) {
this.$small_calendar.datepicker('destroy');
@@ -296,9 +305,9 @@ return AbstractRenderer.extend({
* @override
*/
getLocalState: function () {
- var $fcScroller = this.$calendar.find('.fc-scroller');
+ var fcScroller = this.calendarElement.querySelector('.fc-scroller');
return {
- scrollPosition: $fcScroller.scrollTop(),
+ scrollPosition: fcScroller.scrollTop,
};
},
/**
@@ -306,8 +315,8 @@ return AbstractRenderer.extend({
*/
setLocalState: function (localState) {
if (localState.scrollPosition) {
- var $fcScroller = this.$calendar.find('.fc-scroller');
- $fcScroller.scrollTop(localState.scrollPosition);
+ var fcScroller = this.calendarElement.querySelector('.fc-scroller');
+ fcScroller.scrollTop = localState.scrollPosition;
}
},
@@ -325,14 +334,15 @@ return AbstractRenderer.extend({
var self = this;
var touchStartX;
var touchEndX;
- this.$calendar.on('touchstart', function (event) {
- touchStartX = event.originalEvent.touches[0].pageX;
+ this.calendarElement.addEventListener('touchstart', function (event) {
+ self.isSwipeEnabled = true;
+ touchStartX = event.touches[0].pageX;
});
- this.$calendar.on('touchend', function (event) {
- touchEndX = event.originalEvent.changedTouches[0].pageX;
+ this.calendarElement.addEventListener('touchend', function (event) {
if (!self.isSwipeEnabled) {
return;
}
+ touchEndX = event.changedTouches[0].pageX;
if (touchStartX - touchEndX > 100) {
self.trigger_up('next');
} else if (touchStartX - touchEndX < -100) {
@@ -341,14 +351,43 @@ return AbstractRenderer.extend({
});
},
/**
+ * Convert the new format of Event from FullCalendar V4 to a Event FullCalendar V3
+ * @param fc4Event
+ * @return {Object} FullCalendar V3 Object Event
+ * @private
+ */
+ _convertEventToFC3Event: function (fc4Event) {
+ var event = fc4Event;
+ if (!moment.isMoment(fc4Event.start)) {
+ event = {
+ id: fc4Event.id,
+ title: fc4Event.title,
+ start: moment(fc4Event.start).utcOffset(0, true),
+ end: fc4Event.end && moment(fc4Event.end).utcOffset(0, true),
+ allDay: fc4Event.allDay,
+ color: fc4Event.color,
+ };
+ if (fc4Event.extendedProps) {
+ event = Object.assign({}, event, {
+ r_start: fc4Event.extendedProps.r_start && moment(fc4Event.extendedProps.r_start).utcOffset(0, true),
+ r_end: fc4Event.extendedProps.r_end && moment(fc4Event.extendedProps.r_end).utcOffset(0, true),
+ reset_allday: fc4Event.extendedProps.reset_allday,
+ record: fc4Event.extendedProps.record,
+ attendees: fc4Event.extendedProps.attendees,
+ });
+ }
+ }
+ return event;
+ },
+ /**
* @param {any} event
* @returns {string} the html for the rendered event
*/
_eventRender: function (event) {
var qweb_context = {
event: event,
- record: event.record,
- color: this.getColor(event.color_index),
+ record: event.extendedProps.record,
+ color: this.getColor(event.extendedProps.color_index),
};
this.qweb_context = qweb_context;
if (_.isEmpty(qweb_context.record)) {
@@ -379,43 +418,50 @@ return AbstractRenderer.extend({
_initCalendar: function () {
var self = this;
- this.$calendar = this.$(".o_calendar_widget");
-
- // This seems like a workaround but apparently passing the locale
- // in the options is not enough. We should initialize it beforehand
+ this.calendarElement = this.$(".o_calendar_widget")[0];
var locale = moment.locale();
- $.fullCalendar.locale(locale);
- //Documentation here : http://arshaw.com/fullcalendar/docs/
var fc_options = $.extend({}, this.state.fc_options, {
- eventDrop: function (event) {
+ plugins: [
+ 'moment',
+ 'interaction',
+ 'dayGrid',
+ 'timeGrid'
+ ],
+ eventDrop: function (eventDropInfo) {
+ var event = self._convertEventToFC3Event(eventDropInfo.event);
self.trigger_up('dropRecord', event);
},
- eventResize: function (event) {
+ eventResize: function (eventResizeInfo) {
+ self.isSwipeEnabled = false;
self._unselectEvent();
+ var event = self._convertEventToFC3Event(eventResizeInfo.event);
self.trigger_up('updateRecord', event);
},
- eventClick: function (eventData, ev) {
+ eventClick: function (eventClickInfo) {
+ var eventData = eventClickInfo.event;
self._unselectEvent();
- self.$calendar.find(_.str.sprintf('[data-event-id=%s]', eventData.id)).addClass('o_cw_custom_highlight');
- self._renderEventPopover(eventData, $(ev.currentTarget));
+ $(self.calendarElement).find(_.str.sprintf('[data-event-id=%s]', eventData.id)).addClass('o_cw_custom_highlight');
+ self._renderEventPopover(eventData, $(eventClickInfo.el));
},
- select: function (startDate, endDate) {
- self.isSwipeEnabled = false;
+ select: function (selectionInfo) {
// Clicking on the view, dispose any visible popover. Otherwise create a new event.
if (self.$('.o_cw_popover').length) {
self._unselectEvent();
} else {
- var data = {start: startDate, end: endDate};
+ var data = {start: selectionInfo.start, end: selectionInfo.end};
if (self.state.context.default_name) {
data.title = self.state.context.default_name;
}
- self.trigger_up('openCreate', data);
+ self.trigger_up('openCreate', self._convertEventToFC3Event(data));
}
- self.$calendar.fullCalendar('unselect');
+ self.calendar.unselect();
},
- eventRender: function (event, element, view) {
+ eventRender: function (info) {
self.isSwipeEnabled = false;
+ var event = info.event;
+ var element = $(info.el);
+ var view = info.view;
var $render = $(self._eventRender(event));
element.find('.fc-content').html($render.html());
element.addClass($render.attr('class'));
@@ -426,17 +472,17 @@ return AbstractRenderer.extend({
element.find('.fc-content').after($('<div/>', {class: 'fc-bg'}));
}
- if (view.name === 'month' && event.record) {
- var start = event.r_start || event.start;
- var end = event.r_end || event.end;
+ if (view.type === 'dayGridMonth' && event.extendedProps.record) {
+ var start = event.extendedProps.r_start || event.start;
+ var end = event.extendedProps.r_end || event.end;
// Detect if the event occurs in just one day
// note: add & remove 1 min to avoid issues with 00:00
- var isSameDayEvent = start.clone().add(1, 'minute').isSame(end.clone().subtract(1, 'minute'), 'day');
- if (!event.record.allday && isSameDayEvent) {
+ var isSameDayEvent = moment(start).clone().add(1, 'minute').isSame(moment(end).clone().subtract(1, 'minute'), 'day');
+ if (!event.extendedProps.record.allday && isSameDayEvent) {
// For month view: do not show background for non allday, single day events
element.addClass('o_cw_nobg');
- if (event.showTime && !self.hideTime) {
- const displayTime = start.format(self._getDbTimeFormat());
+ if (event.extendedProps.showTime && !self.hideTime) {
+ const displayTime = moment(start).clone().format(self._getDbTimeFormat());
element.find('.fc-content .fc-time').text(displayTime);
}
}
@@ -447,32 +493,36 @@ return AbstractRenderer.extend({
self.trigger_up('edit_event', {id: event.id});
});
},
- eventAfterAllRender: function () {
- self.isSwipeEnabled = true;
+ eventPositioned: function (){
+ self.isSwipeEnabled = false;
},
- viewRender: function (view) {
- // compute mode from view.name which is either 'month', 'agendaWeek' or 'agendaDay'
- var mode = view.name === 'month' ? 'month' : (view.name === 'agendaWeek' ? 'week' : 'day');
+ datesRender: function (info) {
+ // compute mode from view.type which is either 'dayGridMonth', 'timeGridWeek' or 'timeGridDay'
+ var mode = info.view.type === 'dayGridMonth' ? 'month' : (info.view.type === 'timeGridWeek' ? 'week' : 'day');
self.trigger_up('viewUpdated', {
mode: mode,
- title: view.title,
+ title: info.view.title,
});
},
// Add/Remove a class on hover to style multiple days events.
// The css ":hover" selector can't be used because these events
// are rendered using multiple elements.
- eventMouseover: function (eventData) {
- self.$calendar.find(_.str.sprintf('[data-event-id=%s]', eventData.id)).addClass('o_cw_custom_hover');
+ eventMouseEnter: function (mouseEnterInfo) {
+ $(self.calendarElement).find(_.str.sprintf('[data-event-id=%s]', mouseEnterInfo.event.id)).addClass('o_cw_custom_hover');
},
- eventMouseout: function (eventData) {
- self.$calendar.find(_.str.sprintf('[data-event-id=%s]', eventData.id)).removeClass('o_cw_custom_hover');
+ eventMouseLeave: function (mouseLeaveInfo) {
+ if (!mouseLeaveInfo.event.id) {
+ return;
+ }
+ $(self.calendarElement).find(_.str.sprintf('[data-event-id=%s]', mouseLeaveInfo.event.id)).removeClass('o_cw_custom_hover');
},
- eventDragStart: function (eventData) {
- self.$calendar.find(_.str.sprintf('[data-event-id=%s]', eventData.id)).addClass('o_cw_custom_hover');
+ eventDragStart: function (mouseDragInfo) {
+ $(self.calendarElement).find(_.str.sprintf('[data-event-id=%s]', mouseDragInfo.event.id)).addClass('o_cw_custom_hover');
self._unselectEvent();
},
- eventResizeStart: function (eventData) {
- self.$calendar.find(_.str.sprintf('[data-event-id=%s]', eventData.id)).addClass('o_cw_custom_hover');
+ eventResizeStart: function (mouseResizeInfo) {
+ self.isSwipeEnabled = false;
+ $(self.calendarElement).find(_.str.sprintf('[data-event-id=%s]', mouseResizeInfo.event.id)).addClass('o_cw_custom_hover');
self._unselectEvent();
},
eventLimitClick: function () {
@@ -483,23 +533,23 @@ return AbstractRenderer.extend({
self._render();
},
views: {
- day: {
- columnFormat: 'LL'
+ timeGridDay: {
+ columnHeaderFormat: 'LL'
},
- week: {
- columnFormat: 'ddd D'
+ timeGridWeek: {
+ columnHeaderFormat: 'ddd D'
},
- month: {
- columnFormat: config.device.isMobile ? 'ddd' : 'dddd'
+ dayGridMonth: {
+ columnHeaderFormat: config.device.isMobile ? 'ddd' : 'dddd'
}
},
height: 'parent',
unselectAuto: false,
- isRTL: _t.database.parameters.direction === "rtl",
- locale: locale, // reset locale when fullcalendar has already been instanciated before now
+ dir: _t.database.parameters.direction,
+ locale: locale,
});
- this.$calendar.fullCalendar(fc_options);
+ this.calendar = new FullCalendar.Calendar(this.calendarElement, fcOptions);
},
/**
* Initialize the mini calendar in the sidebar
@@ -551,22 +601,10 @@ return AbstractRenderer.extend({
* @returns {Promise}
*/
_render: function () {
- var $calendar = this.$calendar;
- var $fc_view = $calendar.find('.fc-view');
- var scrollPosition = $fc_view.scrollLeft();
-
- $fc_view.scrollLeft(0);
- $calendar.fullCalendar('unselect');
-
- if (scales[this.state.scale] !== $calendar.data('fullCalendar').getView().type) {
- $calendar.fullCalendar('changeView', scales[this.state.scale]);
- }
-
- if (this.target_date !== this.state.target_date.toString()) {
- $calendar.fullCalendar('gotoDate', moment(this.state.target_date));
- this.target_date = this.state.target_date.toString();
+ this.$('.o_calendar_view')[0].prepend(this.calendarElement);
+ if (this._isInDOM) {
+ this._renderCalendar();
}
-
this.$small_calendar.datepicker("setDate", this.state.highlight_date.toDate())
.find('.o_selected_range')
.removeClass('o_color o_selected_range');
@@ -581,23 +619,41 @@ return AbstractRenderer.extend({
$a.not('.ui-state-active').addClass('o_color');
});
- $fc_view.scrollLeft(scrollPosition);
-
- this._unselectEvent();
var filterProm = this._renderFilters();
- this._renderEvents();
- this.$calendar.prependTo(this.$('.o_calendar_view'));
return Promise.all([filterProm, this._super.apply(this, arguments)]);
},
/**
+ * Render the specific code for the FullCalendar when it's in the DOM
+ *
+ * @private
+ */
+ _renderCalendar() {
+ this.calendar.unselect();
+
+ if (scales[this.state.scale] !== this.calendar.view.type) {
+ this.calendar.changeView(scales[this.state.scale]);
+ }
+
+ if (this.target_date !== this.state.target_date.toString()) {
+ this.calendar.gotoDate(moment(this.state.target_date).toDate());
+ this.target_date = this.state.target_date.toString();
+ }
+
+ this._unselectEvent();
+ this._renderEvents();
+ // this._scrollToScrollTime();
+ },
+ /**
* Render all events
*
* @private
*/
_renderEvents: function () {
- this.$calendar.fullCalendar('removeEvents');
- this.$calendar.fullCalendar('addEventSource', this.state.data);
+ this.calendar.getEvents().forEach(function(event) {
+ event.remove();
+ });
+ this.calendar.addEventSource(this.state.data);
},
/**
* Render all filters
@@ -612,7 +668,7 @@ return AbstractRenderer.extend({
filter.destroy();
});
if (this.state.fullWidth) {
- return;
+ return Promise.resolve();
}
return this._renderFiltersOneByOne();
},
@@ -699,12 +755,12 @@ return AbstractRenderer.extend({
canDelete: this.canDelete,
};
- var start = moment(eventData.r_start || eventData.start);
- var end = moment(eventData.r_end || eventData.end);
+ var start = moment((eventData.extendedProps && eventData.extendedProps.r_start) || eventData.start);
+ var end = moment((eventData.extendedProps && eventData.extendedProps.r_end) || eventData.end);
var isSameDayEvent = start.clone().add(1, 'minute').isSame(end.clone().subtract(1, 'minute'), 'day');
// Do not display timing if the event occur across multiple days. Otherwise use user's timing preferences
- if (!this.hideTime && !eventData.record.allday && isSameDayEvent) {
+ if (!this.hideTime && !eventData.extendedProps.record.allday && isSameDayEvent) {
var dbTimeFormat = this._getDbTimeFormat();
context.eventTime.time = start.clone().format(dbTimeFormat) + ' - ' + end.clone().format(dbTimeFormat);
@@ -729,9 +785,9 @@ return AbstractRenderer.extend({
context.eventDate.date = isSameDayEvent ? start.clone().format('dddd, LL') : start.clone().format('LL') + ' - ' + end.clone().format('LL');
}
- if (eventData.record.allday && isSameDayEvent) {
+ if (eventData.extendedProps.record.allday && isSameDayEvent) {
context.eventDate.duration = _t("All day");
- } else if (eventData.record.allday && !isSameDayEvent) {
+ } else if (eventData.extendedProps.record.allday && !isSameDayEvent) {
var daysLocaleData = moment.localeData();
var days = moment.duration(end.diff(start)).days();
context.eventDate.duration = daysLocaleData.relativeTime(days, true, 'dd');
@@ -756,8 +812,8 @@ return AbstractRenderer.extend({
},
trigger: 'manual',
html: true,
- title: eventData.record.display_name,
- template: qweb.render('CalendarView.event.popover.placeholder', {color: this.getColor(eventData.color_index)}),
+ title: eventData.extendedProps.record.display_name,
+ template: qweb.render('CalendarView.event.popover.placeholder', {color: this.getColor(eventData.extendedProps.color_index)}),
container: eventData.allDay ? '.fc-view' : '.fc-scroller',
}
},
@@ -781,6 +837,14 @@ return AbstractRenderer.extend({
}).popover('show');
});
},
+ /**
+ * Scroll to the time set in the FullCalendar parameter
+ * @private
+ */
+ _scrollToScrollTime: function () {
+ var scrollTime = this.calendar.getOption('scrollTime');
+ this.calendar.scrollToTime(scrollTime);
+ },
//--------------------------------------------------------------------------
// Handlers
@@ -812,7 +876,7 @@ return AbstractRenderer.extend({
*/
_onDeleteEvent: function (event) {
this._unselectEvent();
- this.trigger_up('deleteRecord', {id: event.data.id});
+ this.trigger_up('deleteRecord', {id: parseInt(event.data.id, 10)});
},
});
diff --git a/addons/web/static/src/js/views/calendar/calendar_view.js b/addons/web/static/src/js/views/calendar/calendar_view.js
index dfdb41a54e0..881012952b7 100644
--- a/addons/web/static/src/js/views/calendar/calendar_view.js
+++ b/addons/web/static/src/js/views/calendar/calendar_view.js
@@ -22,8 +22,20 @@ var fieldsToGather = [
var CalendarView = AbstractView.extend({
display_name: _lt('Calendar'),
icon: 'fa-calendar',
- jsLibs: ['/web/static/lib/fullcalendar/js/fullcalendar.js'],
- cssLibs: ['/web/static/lib/fullcalendar/css/fullcalendar.css'],
+ jsLibs: [
+ '/web/static/lib/fullcalendar/core/main.js',
+ '/web/static/lib/fullcalendar/interaction/main.js',
+ '/web/static/lib/fullcalendar/moment/main.js',
+ '/web/static/lib/fullcalendar/daygrid/main.js',
+ '/web/static/lib/fullcalendar/timegrid/main.js',
+ '/web/static/lib/fullcalendar/list/main.js'
+ ],
+ cssLibs: [
+ '/web/static/lib/fullcalendar/core/main.css',
+ '/web/static/lib/fullcalendar/daygrid/main.css',
+ '/web/static/lib/fullcalendar/timegrid/main.css',
+ '/web/static/lib/fullcalendar/list/main.css'
+ ],
config: _.extend({}, AbstractView.prototype.config, {
Model: CalendarModel,
Controller: CalendarController,
diff --git a/addons/web/static/src/scss/web_calendar.scss b/addons/web/static/src/scss/web_calendar.scss
index 97c2ef44f5c..cb98cc47129 100644
--- a/addons/web/static/src/scss/web_calendar.scss
+++ b/addons/web/static/src/scss/web_calendar.scss
@@ -90,7 +90,7 @@ $o-cw-filter-avatar-size: 20px;
background: gray('400');
}
- .fc-agenda-view .fc-day-grid .fc-row .fc-content-skeleton {
+ .fc-timeGrid-view .fc-day-grid .fc-row .fc-content-skeleton {
padding: .5em;
}
@@ -107,7 +107,7 @@ $o-cw-filter-avatar-size: 20px;
// ====================================
// ====== Both Day and Week agenda
- .fc-agendaDay-view, .fc-agendaWeek-view {
+ .fc-timeGridDay-view, .fc-timeGridWeek-view {
.fc-axis {
padding-left: $o-horizontal-padding;
}
@@ -167,7 +167,7 @@ $o-cw-filter-avatar-size: 20px;
box-shadow: inset 0 1px 0 gray('400');
}
- .fc-day.fc-widget-content.fc-today.fc-state-highlight {
+ .fc-day.fc-widget-content.fc-today {
border-left-color: rgba($o-cw-color-today, 0.3);
border-right-color: rgba($o-cw-color-today, 0.3);
background: rgba($o-cw-color-today, 0.05 );
@@ -177,7 +177,7 @@ $o-cw-filter-avatar-size: 20px;
// Prevent events with similar color to visually overlap each other
box-shadow: 0 0 0 1px white;
- &.fc-v-event {
+ &.fc-event:not(.fc-h-event) {
border-width: 3px 0 0;
&.fc-not-start {
@@ -197,7 +197,7 @@ $o-cw-filter-avatar-size: 20px;
}
// ====== Day only
- .fc-agendaDay-view .fc-event {
+ .fc-timeGridDay-view .fc-event {
padding: 10px;
font-size: 14px;
@@ -208,13 +208,13 @@ $o-cw-filter-avatar-size: 20px;
}
// ====== Week only
- .fc-agendaWeek-view {
+ .fc-timeGridWeek-view {
.fc-now-indicator {
left: $o-horizontal-padding;
}
// Expand tiny events on hover/select
- .fc-v-event.o_cw_custom_highlight, .fc-v-event.o_cw_custom_hover {
+ .fc-event:not(.fc-h-event).o_cw_custom_highlight, .fc-event:not(.fc-h-event).o_cw_custom_hover {
transition: margin .1s .3s, left .1s .3s, right .1s .3s;
margin: 0!important;
right: 1px!important;
@@ -223,7 +223,7 @@ $o-cw-filter-avatar-size: 20px;
}
// ====== Month only
- .fc-month-view {
+ .fc-dayGridMonth-view {
padding-left: $o-horizontal-padding;
.fc-widget-header {
@@ -319,11 +319,11 @@ $o-cw-filter-avatar-size: 20px;
}
// ====== RTL layout(s)
&.fc-rtl {
- .fc-agendaWeek-view .fc-event {
+ .fc-timeGrid-view .fc-event {
border-width: 0 3px 0 0;
}
- .fc-month-view .fc-event {
+ .fc-dayGridMonth-view .fc-event {
border-width: 0 3px 0 0;
&.fc-not-start {