OWL
data_display
Calendar Year Renderer
Odoo 19 OWL component — Calendar Year Renderer (views)
Live preview
Interactive
Source excerpt
web/static/src/views/calendar/calendar_year/calendar_year_renderer.js
import { getLocalYearAndWeek } from "@web/core/l10n/dates";
import { localization } from "@web/core/l10n/localization";
import { convertRecordToEvent, getColor } from "@web/views/calendar/utils";
import { useCalendarPopover } from "@web/views/calendar/hooks/calendar_popover_hook";
import { useFullCalendar } from "@web/views/calendar/hooks/full_calendar_hook";
import { makeWeekColumn } from "@web/views/calendar/calendar_common/calendar_common_week_column";
import { CalendarYearPopover } from "@web/views/calendar/calendar_year/calendar_year_popover";
import { Component, useEffect, useRef } from "@odoo/owl";
export class CalendarYearRenderer extends Component {
static components = {
Popover: CalendarYearPopover,
};
static template = "web.CalendarYearRenderer";
static props = {
model: Object,
createRecord: Function,
editRecord: Function,
deleteRecord: Function,
isWeekendVisible: { type: Boolean, optional: true },
};
setup() {
this.months = luxon.Info.months();
this.fcs = {};
for (const month of this.months) {
this.fcs[month] = useFullCalendar(
`fullCalendar-${month}`,
this.getOptionsForMonth(month)
);
}
this.popover = useCalendarPopover(this.constructor.components.Popover);
this.rootRef = useRef("root");
useEffect(() => {
this.updateSize();
});
}
get options() {
return {
dayHeaderFormat: "EEEEE",
dateClick: this.onDateClick,
dayCellClassNames: this.getDayCellClassNames,
initialDate: this.props.model.date.toISO(),
initialView: "dayGridMonth",
direction: localization.direction,
droppable: true,
editable: this.props.model.canEdit,
dayMaxEventRows: this.props.model.eventLimit,
eventClassNames: this.eventClassNames,
eventDidMount: this.onEventDidMount,
eventResizableFromStart: true,
events: (_, successCb) => successCb(this.mapRecordsToEvents()),
firstDay: this.props.model.firstDayOfWeek,
headerToolbar: { start: false, center: "title", end: false },
height: "auto",
locale: luxon.Settings.defaultLocale,
longPressDelay: 500,
navLinks: false,
nowIndicator: true,
select: this.onSelect,
selectMinDistance: 5, // needed to not trigger select when click
selectMirror: true,
selectable: this.props.model.canCreate,
showNonCurrentDates: false,
timeZone: luxon.Settings.defaultZone.name,
titleFormat: { month: "long", year: "numeric" },
unselectAuto: false,
weekNumberCalculation: (date) => getLocalYearAndWeek(date).week,
weekNumbers: false,
weekNumberFormat: { week: "numeric" },
windowResize: this.onWindowResize,
eventContent: this.onEventContent,
viewDidMount: this.viewDidMount,
weekends: this.props.isWeekendVisible,
fixedWeekCount: false,
};
}
get customOptions() {
return {
weekNumbersWithinDays: true,
};
}
viewDidMount({ el, view }) {
const showWeek = view.calendar.currentData.options.weekNumbers;
const weekText = view.calendar.currentData.options.weekText;
const weekColumn = !this.customOptions.weekNumbersWithinDays;
if (showWeek && weekColumn) {
makeWeekColumn({ el, weekText });
}
}
mapRecordsToEvents() {
return Object.values(this.props.model.records).map((r) => this.convertRecordToEvent(r));
}
convertRecordToEvent(record) {
return {
...convertRecordToEvent(record, true),
display: "background",
};
}
getDateWithMonth(month) {
return this.props.model.date.set({ month: this.months.indexOf(month) + 1 }).toISO();
}
getOptionsForMonth(month) {
return {
...this.options,
initialDate: this.getDateWithMonth(month),
};
}
getPopoverProps(date, records) {
return {
date,
records,
model: this.props.model,
createRecord: this.props.createRecord,
Registry / API
- Registry name
CalendarYearRenderer- Category
—- Module
web- Slug
calendar-year-renderer- Nav group
data_display