From 1ee00508c948002fd7c4fb5d892b61048972f4e7 Mon Sep 17 00:00:00 2001 From: Romeo Fragomeli Date: Thu, 7 Jan 2021 10:41:35 +0000 Subject: [PATCH 1/6] [REM] web: remove old comment Since odoo/odoo@441d9f65b3b90c37ce812d2addbe5b62d2d88229 this comment is not valid anymore. Related Task ID: 1891957 --- addons/web/static/src/js/views/calendar/calendar_renderer.js | 1 - 1 file changed, 1 deletion(-) 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 806e9d4e03f..ec6c0551a02 100644 --- a/addons/web/static/src/js/views/calendar/calendar_renderer.js +++ b/addons/web/static/src/js/views/calendar/calendar_renderer.js @@ -427,7 +427,6 @@ return AbstractRenderer.extend({ } }, select: function (selectionInfo) { - // Clicking on the view, dispose any visible popover. Otherwise create a new event. if (self.$('.o_cw_popover').length) { self._unselectEvent(); } From cd45fb402758dae5566effe9203e3de4ae9466bf Mon Sep 17 00:00:00 2001 From: Romeo Fragomeli Date: Thu, 7 Jan 2021 12:16:05 +0000 Subject: [PATCH 2/6] [REF] web: remove sprintf when not needed Related Task ID: 1891957 --- .../src/js/views/calendar/calendar_renderer.js | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) 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 ec6c0551a02..fdc2cd5b460 100644 --- a/addons/web/static/src/js/views/calendar/calendar_renderer.js +++ b/addons/web/static/src/js/views/calendar/calendar_renderer.js @@ -405,7 +405,7 @@ return AbstractRenderer.extend({ eventClickInfo.jsEvent.stopPropagation(); var eventData = eventClickInfo.event; self._unselectEvent(); - $(self.calendarElement).find(_.str.sprintf('[data-event-id=%s]', eventData.id)).addClass('o_cw_custom_highlight'); + $(self.calendarElement).find(`[data-event-id=${eventData.id}]`).addClass('o_cw_custom_highlight'); self._renderEventPopover(eventData, $(eventClickInfo.el)); }, yearDateClick: function (info) { @@ -502,20 +502,20 @@ return AbstractRenderer.extend({ // The css ":hover" selector can't be used because these events // are rendered using multiple elements. eventMouseEnter: function (mouseEnterInfo) { - $(self.calendarElement).find(_.str.sprintf('[data-event-id=%s]', mouseEnterInfo.event.id)).addClass('o_cw_custom_hover'); + $(self.calendarElement).find(`[data-event-id=${mouseEnterInfo.event.id}]`).addClass('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'); + $(self.calendarElement).find(`[data-event-id=${mouseLeaveInfo.event.id}]`).removeClass('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.calendarElement).find(`[data-event-id=${mouseDragInfo.event.id}]`).addClass('o_cw_custom_hover'); self._unselectEvent(); }, eventResizeStart: function (mouseResizeInfo) { - $(self.calendarElement).find(_.str.sprintf('[data-event-id=%s]', mouseResizeInfo.event.id)).addClass('o_cw_custom_hover'); + $(self.calendarElement).find(`[data-event-id=${mouseResizeInfo.event.id}]`).addClass('o_cw_custom_hover'); self._unselectEvent(); }, eventLimitClick: function () { @@ -708,7 +708,7 @@ return AbstractRenderer.extend({ if (options.avatar_field) { _.each(options.filters, function (filter) { if (!['all', false].includes(filter.value)) { - var selector = _.str.sprintf('.o_calendar_filter_item[data-value=%s]', filter.value); + var selector = `.o_calendar_filter_item[data-value=${filter.value}]`; sidebarFilter.$el.find(selector).popover({ animation: false, trigger: 'hover', @@ -718,7 +718,7 @@ return AbstractRenderer.extend({ delay: {show: 300, hide: 0}, content: function () { return $('', { - src: _.str.sprintf('/web/image/%s/%s/%s', options.avatar_model, filter.value, options.avatar_field), + src: `/web/image/${options.avatar_model}/${filter.value}/${options.avatar_field}}`, class: 'mx-auto', }); }, From 7ffa4ddb692f1eb957eba01589cd098f5d917e82 Mon Sep 17 00:00:00 2001 From: Romeo Fragomeli Date: Thu, 7 Jan 2021 15:32:58 +0000 Subject: [PATCH 3/6] [REF] web: allow to reuse the openCreate This will be used in a future commit for "Mobile" (enterprise) Related Task ID: 1891957 --- .../js/views/calendar/calendar_renderer.js | 27 ++++++++++--------- 1 file changed, 15 insertions(+), 12 deletions(-) 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 fdc2cd5b460..44d2a81f773 100644 --- a/addons/web/static/src/js/views/calendar/calendar_renderer.js +++ b/addons/web/static/src/js/views/calendar/calendar_renderer.js @@ -375,6 +375,20 @@ return AbstractRenderer.extend({ return field_utils.format[field.type](record[fieldName], field, {forceString: true}); } }, + _preOpenCreate: function (data) { + if (this.$('.o_cw_popover').length) { + this._unselectEvent(); + } + if (this.state.context.default_name) { + data.title = this.state.context.default_name; + } + this.trigger_up('openCreate', this._convertEventToFC3Event(data)); + if (this.state.scale === 'year') { + this.calendar.view.unselect(); + } else { + this.calendar.unselect(); + } + }, /** * Return the Object options for FullCalendar * @@ -427,19 +441,8 @@ return AbstractRenderer.extend({ } }, select: function (selectionInfo) { - if (self.$('.o_cw_popover').length) { - self._unselectEvent(); - } var data = {start: selectionInfo.start, end: selectionInfo.end, allDay: selectionInfo.allDay}; - if (self.state.context.default_name) { - data.title = self.state.context.default_name; - } - self.trigger_up('openCreate', self._convertEventToFC3Event(data)); - if (self.state.scale === 'year') { - self.calendar.view.unselect(); - } else { - self.calendar.unselect(); - } + self._preOpenCreate(data); }, eventRender: function (info) { var event = info.event; From 3552d46037548fa13dad94efd085e028f753d1a6 Mon Sep 17 00:00:00 2001 From: Romeo Fragomeli Date: Thu, 7 Jan 2021 15:24:10 +0000 Subject: [PATCH 4/6] [FIX] web: restore disableQuickCreate on calendar event Since commit odoo/odoo@ebce7719b624136da2b26a73acf8930538c7a38c the disableQuickCreate parameter was lost during the process. Note: there is no steps to reproduce as this feature was never used. Related Task ID: 1891957 --- .../js/views/calendar/calendar_renderer.js | 1 + .../web/static/tests/views/calendar_tests.js | 50 +++++++++++++++++++ 2 files changed, 51 insertions(+) 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 44d2a81f773..9bc9aa0cb85 100644 --- a/addons/web/static/src/js/views/calendar/calendar_renderer.js +++ b/addons/web/static/src/js/views/calendar/calendar_renderer.js @@ -338,6 +338,7 @@ return AbstractRenderer.extend({ r_end: fc4Event.extendedProps.r_end && moment(fc4Event.extendedProps.r_end).utcOffset(0, true), record: fc4Event.extendedProps.record, attendees: fc4Event.extendedProps.attendees, + disableQuickCreate: fc4Event.extendedProps.disableQuickCreate, }); } } diff --git a/addons/web/static/tests/views/calendar_tests.js b/addons/web/static/tests/views/calendar_tests.js index 308ac98fde8..46d6019328f 100644 --- a/addons/web/static/tests/views/calendar_tests.js +++ b/addons/web/static/tests/views/calendar_tests.js @@ -3938,6 +3938,56 @@ QUnit.module('Views', { calendar.destroy(); }); + + QUnit.test('calendar: disableQuickCreate in data event', async function (assert) { + assert.expect(3); + + testUtils.mock.patch(CalendarRenderer, { + _preOpenCreate: function (data) { + data = Object.assign({}, data, { + extendedProps: {disableQuickCreate: true}, + }); + return this._super.call(this, data); + }, + }); + + let calendar = await testUtils.createCalendarView({ + View: CalendarView, + model: 'event', + data: this.data, + arch: ``, + viewOptions: { + initialDate: initialDate, + }, + intercepts: { + do_action(ev) { + assert.step('do_action'); + assert.deepEqual(ev.data.action.context, { + default_start: "2016-12-12 06:30:00", + default_stop: "2016-12-12 11:00:00", + }, "should send the correct data to create events"); + }, + }, + }, {positionalClicks: true}); + + // Create event + var $initCell = calendar.$('.fc-time-grid .fc-minor[data-time="06:30:00"] .fc-widget-content:last-child'); + var $endCell = calendar.$('.fc-time-grid .fc-minor[data-time="10:30:00"] .fc-widget-content:last-child'); + + var left = $initCell.offset().left; + var top = $initCell.offset().top; + testUtils.dom.triggerPositionalMouseEvent(left, top, "mousedown"); + top = $endCell.offset().top; + testUtils.dom.triggerPositionalMouseEvent(left, top, "mousemove"); + testUtils.dom.triggerPositionalMouseEvent(left, top, "mouseup"); + await testUtils.nextTick(); + + assert.verifySteps(['do_action']); + + calendar.destroy(); + + testUtils.mock.unpatch(CalendarRenderer); + }); }); }); From c96e3b96f307685d03d240fac81fb0e83ca85f1d Mon Sep 17 00:00:00 2001 From: Romeo Fragomeli Date: Wed, 20 Jan 2021 09:27:45 +0000 Subject: [PATCH 5/6] [IMP] web: add support for TAP events in test utils This commit add the support to simulate a "TAP" (touch) using coordinate. This utils will be used in a future commit in web_enterprise to be able to test some specific case for FullCalendar. Task ID: 1891957 --- addons/web/static/tests/helpers/test_utils.js | 1 + .../static/tests/helpers/test_utils_dom.js | 50 +++++++++++++++++++ 2 files changed, 51 insertions(+) diff --git a/addons/web/static/tests/helpers/test_utils.js b/addons/web/static/tests/helpers/test_utils.js index 863a9edc993..1ce6dac94ee 100644 --- a/addons/web/static/tests/helpers/test_utils.js +++ b/addons/web/static/tests/helpers/test_utils.js @@ -197,6 +197,7 @@ odoo.define('web.test_utils', async function (require) { triggerKeypressEvent: testUtilsDom.triggerKeypressEvent, triggerMouseEvent: testUtilsDom.triggerMouseEvent, triggerPositionalMouseEvent: testUtilsDom.triggerPositionalMouseEvent, + triggerPositionalTapEvents: testUtilsDom.triggerPositionalTapEvents, dragAndDrop: testUtilsDom.dragAndDrop, find: testUtilsDom.findItem, getNode: testUtilsDom.getNode, diff --git a/addons/web/static/tests/helpers/test_utils_dom.js b/addons/web/static/tests/helpers/test_utils_dom.js index eedbcbe5155..f85fe9bec8b 100644 --- a/addons/web/static/tests/helpers/test_utils_dom.js +++ b/addons/web/static/tests/helpers/test_utils_dom.js @@ -33,6 +33,17 @@ odoo.define('web.test_utils_dom', function (require) { clientY: args ? args.pageY : undefined, view: window, }); + const touchEventMapping = args => Object.assign({}, args, { + cancelable: true, + bubbles: true, + composed: true, + view: window, + rotation: 0.0, + zoom: 1.0, + }); + const touchEventCancelMapping = args => Object.assign({}, touchEventMapping(args), { + cancelable: false, + }); const noBubble = args => Object.assign({}, args, { bubbles: false }); const onlyBubble = args => Object.assign({}, args, { bubbles: true }); // TriggerEvent constructor/args processor mapping @@ -70,6 +81,11 @@ odoo.define('web.test_utils_dom', function (require) { dragover: { constructor: DragEvent, processParameters: onlyBubble }, drop: { constructor: DragEvent, processParameters: onlyBubble }, + touchstart: { constructor: TouchEvent, processParameters: touchEventMapping }, + touchend: { constructor: TouchEvent, processParameters: touchEventMapping }, + touchmove: { constructor: TouchEvent, processParameters: touchEventMapping }, + touchcancel: { constructor: TouchEvent, processParameters: touchEventCancelMapping }, + input: { constructor: InputEvent, processParameters: onlyBubble }, compositionstart: { constructor: CompositionEvent, processParameters: onlyBubble }, @@ -533,6 +549,39 @@ odoo.define('web.test_utils_dom', function (require) { return el; } + /** + * Simulate a "TAP" (touch) event with a custom position x and y. + * + * @param {number} x + * @param {number} y + * @returns {HTMLElement} + */ + async function triggerPositionalTapEvents(x, y) { + const element = document.elementFromPoint(x, y); + const touch = new Touch({ + identifier: 0, + target: element, + clientX: x, + clientY: y, + pageX: x, + pageY: y, + }); + await triggerEvent(element, 'touchstart', { + touches: [touch], + targetTouches: [touch], + changedTouches: [touch], + }); + await triggerEvent(element, 'touchmove', { + touches: [touch], + targetTouches: [touch], + changedTouches: [touch], + }); + await triggerEvent(element, 'touchend', { + changedTouches: [touch], + }); + return element; + } + return { click, clickFirst, @@ -547,5 +596,6 @@ odoo.define('web.test_utils_dom', function (require) { triggerKeypressEvent, triggerMouseEvent, triggerPositionalMouseEvent, + triggerPositionalTapEvents, }; }); From ef9ecf1388928f9bd381268ce575691d39ddfaf4 Mon Sep 17 00:00:00 2001 From: Romeo Fragomeli Date: Wed, 27 Jan 2021 15:37:01 +0000 Subject: [PATCH 6/6] [IMP] web: allow to change the scale also when changing the date This commit allow to change the scale at the same time as changing the date. Task ID: 1891957 --- addons/web/static/src/js/views/calendar/calendar_controller.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/addons/web/static/src/js/views/calendar/calendar_controller.js b/addons/web/static/src/js/views/calendar/calendar_controller.js index e354902c131..43afd983fb3 100644 --- a/addons/web/static/src/js/views/calendar/calendar_controller.js +++ b/addons/web/static/src/js/views/calendar/calendar_controller.js @@ -236,6 +236,9 @@ var CalendarController = AbstractController.extend({ // When clicking on a random day of a random other week, switch to week view this.model.setScale('week'); } + if (event.data.scale) { + this.model.setScale(event.data.scale); + } this.model.setDate(event.data.date); this.reload(); },