Skip to Content
OWL data_display

Calendar Common Renderer

Odoo 19 OWL component — Calendar Common Renderer (views)

Live preview Interactive
Source excerpt web/static/src/views/calendar/calendar_common/calendar_common_renderer.js
import { browser } from "@web/core/browser/browser";
import { getLocalYearAndWeek } from "@web/core/l10n/dates";
import { localization } from "@web/core/l10n/localization";
import { is24HourFormat } from "@web/core/l10n/time";
import { useBus } from "@web/core/utils/hooks";
import { renderToFragment, renderToString } from "@web/core/utils/render";
import { useDebounced } from "@web/core/utils/timing";
import { makeWeekColumn } from "@web/views/calendar/calendar_common/calendar_common_week_column";
import { CalendarCommonPopover } from "@web/views/calendar/calendar_common/calendar_common_popover";
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 { useSquareSelection } from "@web/views/calendar/hooks/square_selection_hook";

import { Component, useEffect } from "@odoo/owl";

const SCALE_TO_FC_VIEW = {
    day: "timeGridDay",
    week: "timeGridWeek",
    month: "dayGridMonth",
};
const SCALE_TO_HEADER_FORMAT = {
    day: "DDD",
    week: "EEE d",
    month: "EEEE",
};
const SHORT_SCALE_TO_HEADER_FORMAT = {
    ...SCALE_TO_HEADER_FORMAT,
    day: "D",
    month: "EEE",
};
const HOUR_FORMATS = {
    12: {
        hour: "numeric",
        minute: "2-digit",
        omitZeroMinute: true,
        meridiem: "short",
    },
    24: {
        hour: "numeric",
        minute: "2-digit",
        hour12: false,
    },
};

const { DateTime } = luxon;

export class CalendarCommonRenderer extends Component {
    static components = {
        Popover: CalendarCommonPopover,
    };
    static template = "web.CalendarCommonRenderer";
    static eventTemplate = "web.CalendarCommonRenderer.event";
    static headerTemplate = "web.CalendarCommonRendererHeader";
    static props = {
        model: Object,
        isWeekendVisible: { type: Boolean, optional: true },
        createRecord: Function,
        editRecord: Function,
        deleteRecord: Function,
        setDate: { type: Function, optional: true },
        callbackRecorder: Object,
        onSquareSelection: Function,
        cleanSquareSelection: Function,
    };

    setup() {
        this.fc = useFullCalendar("fullCalendar", this.options);
        this.clickTimeoutId = null;
        this.popover = useCalendarPopover(this.constructor.components.Popover);
        this.timeFormat = is24HourFormat() ? "HH:mm" : "hh:mm a";
        useBus(this.props.model.bus, "SCROLL_TO_CURRENT_HOUR", () =>
            this.fc.api.scrollToTime(`${luxon.DateTime.local().hour - 2}:00:00`)
        );

        const fullCalendarRenderDebounced = useDebounced(() => this.fc.api.updateSize(), 100, {
            immediate: true,
            trailing: true,
        });
        const fullCalendarResizeObserver = new ResizeObserver(fullCalendarRenderDebounced);
        useEffect(
            (el) => {
                fullCalendarResizeObserver.observe(el);
                return () => fullCalendarResizeObserver.unobserve(el);
            },
            () => [this.fc.el]
        );
        useSquareSelection({
            cellIsSelectable: this.constructor.cellIsSelectable,
        });
    }

    get options() {
        return {
            allDaySlot: true,
            allDayContent: "",
            dayHeaderFormat: this.env.isSmall
                ? SHORT_SCALE_TO_HEADER_FORMAT[this.props.model.scale]
                : SCALE_TO_HEADER_FORMAT[this.props.model.scale],
            // we must handle clicks differently in multicreate mode:
            // fc is blocked by safePrevent in onPointerDown (draggable_hook_builder.js)
            dateClick: this.props.model.hasMultiCreate ? () => {} : this.onDateClick,
            dayCellClassNames: this.getDayCellClassNames,
            initialDate: this.props.model.date.toISO(),
            initialView: SCALE_TO_FC_VIEW[this.props.model.scale],
            direction: localization.direction,
            droppable: true,
            editable: this.props.model.canEdit,
            eventClick: this.onEventClick,
            eventDragStart: this.onEventDragStart,
            eventDrop: this.onEventDrop,
            dayMaxEventRows: this.props.model.eventLimit,
            moreLinkClick: this.onEventLimitClick,
            eventMouseEnter: this.onEventMouseEnter,
            eventMouseLeave: this.onEventMouseLeave,
            eventClassNames: this.eventClassNames,
            eventDidMount: this.onEventDidMount,
            eventContent: this.onEventContent,
            eventResizableFromStart: true,
            eventResize: this.onEventResize,
Registry / API
Registry name
CalendarCommonRenderer
Category
Module
web
Slug
calendar-common-renderer
Nav group
data_display