diff --git a/web_view_calendar_list/README.rst b/web_view_calendar_list/README.rst index 45ea139c4..fa6ac5859 100644 --- a/web_view_calendar_list/README.rst +++ b/web_view_calendar_list/README.rst @@ -23,7 +23,7 @@ Web View Calendar List :target: https://runbot.odoo-community.org/runbot/162/13.0 :alt: Try me on Runbot -|badge1| |badge2| |badge3| |badge4| |badge5| +|badge1| |badge2| |badge3| |badge4| |badge5| This module adds a new view type that can be used to show calendars as lists. @@ -38,9 +38,10 @@ Usage Create a new view using the calendar_list tag. It has the same options than calendar:: - - - + + + + Bug Tracker diff --git a/web_view_calendar_list/__manifest__.py b/web_view_calendar_list/__manifest__.py index 6ebd9d975..10e0927d1 100644 --- a/web_view_calendar_list/__manifest__.py +++ b/web_view_calendar_list/__manifest__.py @@ -5,7 +5,7 @@ "name": "Web View Calendar List", "summary": """ Show calendars as a List""", - "version": "13.0.1.0.0", + "version": "14.0.1.0.0", "license": "AGPL-3", "author": "Creu Blanca,Odoo Community Association (OCA)", "website": "https://github.com/OCA/web", diff --git a/web_view_calendar_list/models/ir_actions_act_window_view.py b/web_view_calendar_list/models/ir_actions_act_window_view.py index 3b40c8bfe..d2468dfa0 100644 --- a/web_view_calendar_list/models/ir_actions_act_window_view.py +++ b/web_view_calendar_list/models/ir_actions_act_window_view.py @@ -7,4 +7,7 @@ from odoo import fields, models class IrActionsActWindowView(models.Model): _inherit = "ir.actions.act_window.view" - view_mode = fields.Selection(selection_add=[("calendar_list", "Calendar List")]) + view_mode = fields.Selection( + selection_add=[("calendar_list", "Calendar List")], + ondelete={"calendar_list": "cascade"}, + ) diff --git a/web_view_calendar_list/models/ir_ui_view.py b/web_view_calendar_list/models/ir_ui_view.py index 277a34369..41a86a7dc 100644 --- a/web_view_calendar_list/models/ir_ui_view.py +++ b/web_view_calendar_list/models/ir_ui_view.py @@ -7,4 +7,7 @@ from odoo import fields, models class IrUiView(models.Model): _inherit = "ir.ui.view" - type = fields.Selection(selection_add=[("calendar_list", "Calendar List")]) + type = fields.Selection( + selection_add=[("calendar_list", "Calendar List")], + ondelete={"calendar_list": "cascade"}, + ) diff --git a/web_view_calendar_list/static/src/js/calendar_list_controller.js b/web_view_calendar_list/static/src/js/calendar_list_controller.js index dbe446ca4..470e6cdd3 100644 --- a/web_view_calendar_list/static/src/js/calendar_list_controller.js +++ b/web_view_calendar_list/static/src/js/calendar_list_controller.js @@ -1,9 +1,5 @@ odoo.define("web_view_calendar_list.CalendarListController", function (require) { "use strict"; - var CalendarController = require("web.CalendarController"); - - var CalendarListController = CalendarController.extend({}); - - return CalendarListController; + return CalendarController.extend({}); }); diff --git a/web_view_calendar_list/static/src/js/calendar_list_model.js b/web_view_calendar_list/static/src/js/calendar_list_model.js index 0b81bcc36..d45ad9adf 100644 --- a/web_view_calendar_list/static/src/js/calendar_list_model.js +++ b/web_view_calendar_list/static/src/js/calendar_list_model.js @@ -1,57 +1,5 @@ odoo.define("web_view_calendar_list.CalendarListModel", function (require) { "use strict"; - var CalendarModel = require("web.CalendarModel"); - - var AppointmentModel = CalendarModel.extend({ - _recordToCalendarEvent: function (evt) { - var date_start = false; - var date_stop = false; - var date_delay = evt[this.mapping.date_delay] || 1.0, - all_day = - this.fields[this.mapping.date_start].type === "date" || - (this.mapping.all_day && evt[this.mapping.all_day]) || - false, - the_title = "", - attendees = []; - - if (all_day) { - date_start = evt[this.mapping.date_start].clone().startOf("day"); - date_stop = this.mapping.date_stop - ? evt[this.mapping.date_stop].clone().startOf("day") - : null; - } else { - date_start = evt[this.mapping.date_start].clone(); - date_stop = this.mapping.date_stop - ? evt[this.mapping.date_stop].clone() - : null; - } - - if (!date_stop && date_delay) { - date_stop = date_start.clone().add(date_delay, "hours"); - } - - if (!all_day) { - date_start.add(this.getSession().getTZOffset(date_start), "minutes"); - date_stop.add(this.getSession().getTZOffset(date_stop), "minutes"); - } - - if (this.mapping.all_day && evt[this.mapping.all_day]) { - date_stop.add(1, "days"); - } - return { - record: evt, - start: date_start, - end: date_stop, - r_start: date_start, - r_end: date_stop, - title: the_title, - allDay: all_day, - id: evt.id, - attendees: attendees, - }; - }, - }); - - return AppointmentModel; + return CalendarModel.extend({}); }); diff --git a/web_view_calendar_list/static/src/js/calendar_list_renderer.js b/web_view_calendar_list/static/src/js/calendar_list_renderer.js index 6de49d427..fe9a63b7b 100644 --- a/web_view_calendar_list/static/src/js/calendar_list_renderer.js +++ b/web_view_calendar_list/static/src/js/calendar_list_renderer.js @@ -1,164 +1,82 @@ odoo.define("web_view_calendar_list.CalendarListRenderer", function (require) { "use strict"; - var CalendarRenderer = require("web.CalendarRenderer"); - var core = require("web.core"); - var _t = core._t; + const CalendarRenderer = require("web.CalendarRenderer"); + const core = require("web.core"); + const _t = core._t; - var scales = { - day: "listDay", - week: "listWeek", - month: "listMonth", - }; - - var AppointmentRenderer = CalendarRenderer.extend({ - _initCalendar: function () { + return CalendarRenderer.extend({ + _getFullCalendarOptions: function (fcOptions) { 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 - 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) { - self.trigger_up("dropRecord", event); - }, - eventResize: function (event) { - self.trigger_up("updateRecord", event); - }, - eventClick: function (event) { - self.trigger_up("openEvent", event); - self.$calendar.fullCalendar("unselect"); - }, - select: function (target_date, end_date) { - var data = {start: target_date, end: end_date}; - if (self.state.context.default_name) { - data.title = self.state.context.default_name; - } - self.trigger_up("openCreate", data); - self.$calendar.fullCalendar("unselect"); - }, - eventRender: function (event, element) { - var $render = $(self._eventRender(event)); - event.title = $render.find(".o_field_type_char:first").text(); - element.find(".fc-list-item-title").html($render.html()); - element.addClass($render.attr("class")); - var display_hour = ""; - if (!event.allDay) { - var start = event.r_start || event.start; - var end = event.r_end || event.end; - var timeFormat = - _t.database.parameters.time_format.search("%H") == -1 - ? "h:mma" - : "HH:mm"; - display_hour = - start.format(timeFormat) + " - " + end.format(timeFormat); - if (display_hour === "00:00 - 00:00") { - display_hour = _t("All day"); + return this._super( + _.extend({}, fcOptions, { + viewRender: function (view) { + // Compute mode from view.name which is either 'month', + // 'agendaWeek' or 'agendaDay' + var mode = + view.name === "listMonth" + ? "month" + : view.name === "listWeek" + ? "week" + : "day"; + // Compute title: in week mode, display the week number + var title = + mode === "week" + ? _t("Week ") + view.intervalStart.week() + : view.title; + self.trigger_up("viewUpdated", { + mode: mode, + title: title, + }); + }, + views: { + listDay: { + columnHeaderFormat: "LL", + }, + listWeek: { + columnHeaderFormat: "ddd D", + }, + listMonth: { + columnHeaderFormat: "dddd", + }, + }, + eventRender: function (info) { + var event = info.event; + var element = $(info.el); + element.attr("data-event-id", event.id); + var $render = $(self._eventRender(event)); + element.find(".fc-list-item-title").html($render.html()); + element.addClass($render.attr("class")); + var color = self.getColor(event.extendedProps.color_index); + if (typeof color === "number") { + element + .find(".fc-event-dot") + .addClass(_.str.sprintf("o_calendar_color_%s", color)); + } else { + element + .find(".fc-event-dot") + .addClass("o_calendar_color_1"); } - } - element.find(".fc-list-item-time").text(display_hour); - }, - // Dirty hack to ensure a correct first render - windowResize: function () { - self._render(); - }, - viewRender: function (view) { - // Compute mode from view.name which is either 'month', - // 'agendaWeek' or 'agendaDay' - var mode = - view.name === "listMonth" - ? "month" - : view.name === "listWeek" - ? "week" - : "day"; - // Compute title: in week mode, display the week number - var title = - mode === "week" - ? _t("Week ") + view.intervalStart.week() - : view.title; - self.trigger_up("viewUpdated", { - mode: mode, - title: title, - }); - }, - height: "parent", - unselectAuto: false, - isRTL: _t.database.parameters.direction === "rtl", - locale: locale, - /* Reset locale when fullcalendar has already been - instanciated before now - */ - }); - - this.$calendar.fullCalendar(fc_options); - }, - /* - We need to overwrite it in order make a change on the state variable - that is not dependant on the class, so we cannot modify it without - overwriting all the class - */ - _render: function () { - var $calendar = this.$calendar; - var $fc_view = $calendar.find(".fc-view"); - var scrollPosition = $fc_view.scrollLeft(); - var scrollTop = this.$calendar.find(".fc-scroller").scrollTop(); - - $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.$small_calendar - .datepicker("setDate", this.state.highlight_date.toDate()) - .find(".o_selected_range") - .removeClass("o_color o_selected_range"); - var $a = false; - switch (this.state.scale) { - case "month": - $a = this.$small_calendar.find("td a"); - break; - case "week": - $a = this.$small_calendar.find("tr:has(.ui-state-active) a"); - break; - case "day": - $a = this.$small_calendar.find("a.ui-state-active"); - break; - } - $a.addClass("o_selected_range"); - setTimeout(function () { - $a.not(".ui-state-active").addClass("o_color"); - }); - - $fc_view.scrollLeft(scrollPosition); - - this._renderFilters(); - this.$calendar.appendTo("body"); - if (scrollTop) { - this.$calendar.fullCalendar("reinitView"); - } else { - this.$calendar.fullCalendar("render"); - } - this._renderEvents(); - this.$calendar.prependTo(this.$(".o_calendar_view")); - - return $.when(); + if (typeof color === "string") { + element + .find(".fc-event-dot") + .css("background-color", color); + } + // Add background if doesn't exist + if (!element.find(".fc-bg").length) { + element + .find(".fc-content") + .after($("
", {class: "fc-bg"})); + } + // On double click, edit the event + element.on("dblclick", function () { + self.trigger_up("edit_event", {id: event.id}); + }); + }, + plugins: ["list"], + isRTL: _t.database.parameters.direction === "rtl", + }) + ); }, }); - - return AppointmentRenderer; }); diff --git a/web_view_calendar_list/static/src/js/calendar_list_view.js b/web_view_calendar_list/static/src/js/calendar_list_view.js index cc1e2347e..7edd02037 100644 --- a/web_view_calendar_list/static/src/js/calendar_list_view.js +++ b/web_view_calendar_list/static/src/js/calendar_list_view.js @@ -9,6 +9,12 @@ odoo.define("web_view_calendar_list.CalendarListView", function (require) { var view_registry = require("web.view_registry"); var _lt = core._lt; + const scalesInfo = { + day: "listDay", + week: "listWeek", + month: "listMonth", + }; + const allowedScales = Object.keys(scalesInfo); var CalendarListView = CalendarView.extend({ display_name: _lt("Calendar List"), @@ -18,6 +24,19 @@ odoo.define("web_view_calendar_list.CalendarListView", function (require) { Controller: CalendarListController, Renderer: CalendarListRenderer, }), + init: function () { + this._super.apply(this, arguments); + var scales = allowedScales; + if (this.arch.attrs.scales) { + scales = this.arch.attrs.scales + .split(",") + .filter((x) => allowedScales.includes(x)); + } + this.controllerParams.scales = scales; + this.rendererParams.scalesInfo = scalesInfo; + this.loadParams.scales = scales; + this.loadParams.scalesInfo = scalesInfo; + }, }); view_registry.add("calendar_list", CalendarListView); diff --git a/web_view_calendar_list/static/src/scss/web_calendar_list.scss b/web_view_calendar_list/static/src/scss/web_calendar_list.scss new file mode 100644 index 000000000..44a5c3992 --- /dev/null +++ b/web_view_calendar_list/static/src/scss/web_calendar_list.scss @@ -0,0 +1,11 @@ +// Variables +// =============== Generate color classes =============== +@for $i from 1 through length($o-colors-complete) { + $color: nth($o-colors-complete, $i); + + .o_calendar_view .fc-view { + .fc-event-dot.o_calendar_color_#{$i - 1} { + background-color: $color; + } + } +} diff --git a/web_view_calendar_list/templates/assets.xml b/web_view_calendar_list/templates/assets.xml index 8a8002c9a..30ca91b80 100644 --- a/web_view_calendar_list/templates/assets.xml +++ b/web_view_calendar_list/templates/assets.xml @@ -23,6 +23,11 @@ type="text/javascript" src="/web_view_calendar_list/static/src/js/calendar_list_view.js" /> +