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 d49c7c33f5cbb2d55aeb22b7e6baf749c64d4c24..b699879472ab15ccdedaad082e66635f4a1efccc 100644 --- a/addons/web/static/src/js/views/calendar/calendar_controller.js +++ b/addons/web/static/src/js/views/calendar/calendar_controller.js @@ -240,7 +240,10 @@ var CalendarController = AbstractController.extend({ } } - var options = _.extend({}, this.options, event.options, {context: context}); + var options = _.extend({}, this.options, event.options, { + context: context, + title: _.str.sprintf(_t('Create: %s'), (this.displayName || this.renderer.arch.attrs.string)) + }); if (this.quick != null) { this.quick.destroy(); 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 63a35171a3053858cbbd41a66f000803b551c33f..1f8c9423cac01345546299d7df92406214f5e9cb 100644 --- a/addons/web/static/src/js/views/calendar/calendar_model.js +++ b/addons/web/static/src/js/views/calendar/calendar_model.js @@ -405,6 +405,7 @@ return AbstractModel.extend({ dayNames: moment.weekdays(), dayNamesShort: moment.weekdaysShort(), firstDay: _t.database.parameters.week_start, + slotLabelFormat: _t.database.parameters.time_format.search("%H") != -1 ? 'H:mm': 'h(:mm)a', }; }, /** diff --git a/addons/web/static/src/js/views/calendar/calendar_quick_create.js b/addons/web/static/src/js/views/calendar/calendar_quick_create.js index 698c5d8895a6d0a725a60ac84c0d766153acdf04..8329ca83bd8106d76881c76e8d7d8ce332206a3f 100644 --- a/addons/web/static/src/js/views/calendar/calendar_quick_create.js +++ b/addons/web/static/src/js/views/calendar/calendar_quick_create.js @@ -39,7 +39,7 @@ var QuickCreate = Dialog.extend({ var self = this; this._super(parent, { - title: this._getTitle(), + title: options.title, size: 'small', buttons: this._buttons ? [ {text: _t("Create"), classes: 'btn-primary', click: function () { @@ -68,22 +68,9 @@ var QuickCreate = Dialog.extend({ }, //-------------------------------------------------------------------------- - // Public + // Private //-------------------------------------------------------------------------- - /** - * @returns {string} - */ - _getTitle: function () { - var parent = this.getParent(); - if (_.isUndefined(parent)) { - return _t("Create"); - } - var title = (_.isUndefined(parent.field_widget)) ? - (parent.title || parent.string || parent.name) : - (parent.field_widget.string || parent.field_widget.name || ''); - return _t("Create: ") + title; - }, /** * Gathers data from the quick create dialog a launch quick_create(data) method */ @@ -93,6 +80,11 @@ var QuickCreate = Dialog.extend({ dataCalendar.title = val; return (val)? this.trigger_up('quickCreate', {data: dataCalendar, options: this.options}) : false; }, + + //-------------------------------------------------------------------------- + // Handlers + //-------------------------------------------------------------------------- + /** * @private * @param {keyEvent} event 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 a8d5d07ed0d61f78dbd78e9a4a6b668caa68f3ed..4b4050b67ccf8d37beea293c6fe392eec642d8ee 100644 --- a/addons/web/static/src/js/views/calendar/calendar_renderer.js +++ b/addons/web/static/src/js/views/calendar/calendar_renderer.js @@ -78,6 +78,9 @@ var SidebarFilter = Widget.extend(FieldManagerMixin, { { mode: 'edit', can_create: false, + attrs: { + 'placeholder': _.str.sprintf(_t("Add %s"), self.title), + }, }); }); defs.push(def); @@ -388,7 +391,8 @@ return AbstractRenderer.extend({ if (!event.allDay) { var start = event.r_start || event.start; var end = event.r_end || event.end; - display_hour = start.format('HH:mm') + ' - ' + end.format('HH:mm'); + var timeFormat = _t.database.parameters.time_format.search("%H") != -1 ? 'HH:mm': 'h:mma'; + display_hour = start.format(timeFormat) + ' - ' + end.format(timeFormat); if (display_hour === '00:00 - 00:00') { display_hour = _t('All day'); } diff --git a/addons/web/static/tests/views/calendar_tests.js b/addons/web/static/tests/views/calendar_tests.js index 9728d8a7c74bdc4f71f5571c4a90da112e4e7011..0a7ca319c2f33a03f71e27f175de8e84ed61d740 100644 --- a/addons/web/static/tests/views/calendar_tests.js +++ b/addons/web/static/tests/views/calendar_tests.js @@ -439,7 +439,7 @@ QUnit.module('Views', { testUtils.triggerMouseEvent($cell, "mousedown"); testUtils.triggerMouseEvent($cell, "mouseup"); - assert.strictEqual($('.modal-dialog.modal-sm .modal-title').text(), 'Create', + assert.strictEqual($('.modal-dialog.modal-sm .modal-title').text(), 'Create: Events', "should open the quick create dialog"); $('.modal-body input:first').val('new event in quick create').trigger('input'); @@ -456,7 +456,7 @@ QUnit.module('Views', { calendar.destroy(); }); - QUnit.test('create event with timezone in week mode', function (assert) { + QUnit.test('create event with timezone in week mode European locale', function (assert) { assert.expect(5); this.data.event.records = []; @@ -486,6 +486,9 @@ QUnit.module('Views', { return 120; }, }, + translateParameters: { // Avoid issues due to localization formats + time_format: "%H:%M:%S", + }, mockRPC: function (route, args) { if (args.method === "create") { assert.deepEqual(args.kwargs.context, { @@ -504,7 +507,7 @@ QUnit.module('Views', { var $view = $('#qunit-fixture').contents(); $view.prependTo('body'); // => select with click position - var top = calendar.$('.fc-axis:contains(8am)').offset().top + 5; + var top = calendar.$('.fc-axis:contains(8:00)').offset().top + 5; var left = calendar.$('.fc-day:eq(2)').offset().left + 5; try { @@ -550,7 +553,7 @@ QUnit.module('Views', { $view.remove(); }); - QUnit.test('create event with timezone in week mode with formViewDialog', function (assert) { + QUnit.test('create event with timezone in week mode with formViewDialog European locale', function (assert) { assert.expect(8); this.data.event.records = []; @@ -589,6 +592,9 @@ QUnit.module('Views', { return 120; }, }, + translateParameters: { // Avoid issues due to localization formats + time_format: "%H:%M:%S", + }, mockRPC: function (route, args) { if (args.method === "create") { assert.deepEqual(args.kwargs.context, { @@ -610,7 +616,7 @@ QUnit.module('Views', { var $view = $('#qunit-fixture').contents(); $view.prependTo('body'); // => select with click position - var top = calendar.$('.fc-axis:contains(8am)').offset().top + 5; + var top = calendar.$('.fc-axis:contains(8:00)').offset().top + 5; var left = calendar.$('.fc-day:eq(2)').offset().left + 5; try { @@ -699,6 +705,282 @@ QUnit.module('Views', { $view.remove(); }); + QUnit.test('create event with timezone in week mode American locale', function (assert) { + assert.expect(5); + + this.data.event.records = []; + + var calendar = createView({ + View: CalendarView, + model: 'event', + data: this.data, + arch: + '<calendar class="o_calendar_test" '+ + 'event_open_popup="true" '+ + 'date_start="start" '+ + 'date_stop="stop" '+ + 'all_day="allday" '+ + 'mode="week" '+ + 'readonly_form_view_id="1">'+ + '<field name="name"/>'+ + '<field name="start"/>'+ + '<field name="allday"/>'+ + '</calendar>', + archs: archs, + viewOptions: { + initialDate: initialDate, + }, + session: { + getTZOffset: function () { + return 120; + }, + }, + translateParameters: { // Avoid issues due to localization formats + time_format: "%I:%M:%S", + }, + mockRPC: function (route, args) { + if (args.method === "create") { + assert.deepEqual(args.kwargs.context, { + "default_name": null, + "default_start": "2016-12-13 06:00:00", + "default_stop": "2016-12-13 08:00:00", + "default_allday": null + }, + "should send the context to create events"); + } + return this._super(route, args); + }, + }); + + + var $view = $('#qunit-fixture').contents(); + $view.prependTo('body'); // => select with click position + + var top = calendar.$('.fc-axis:contains(8am)').offset().top + 5; + var left = calendar.$('.fc-day:eq(2)').offset().left + 5; + + try { + testUtils.triggerPositionalMouseEvent(left, top, "mousedown"); + } catch (e) { + calendar.destroy(); + $view.remove(); + throw new Error('The test fails to simulate a click in the screen. Your screen is probably too small or your dev tools is open.'); + } + + testUtils.triggerPositionalMouseEvent(left, top + 60, "mousemove"); + + assert.strictEqual(calendar.$('.fc-content .fc-time').text(), "8:00am - 10:00am", + "should display the time in the calendar sticker"); + + testUtils.triggerPositionalMouseEvent(left, top + 60, "mouseup"); + $('.modal input:first').val('new event').trigger('input'); + $('.modal button.btn:contains(Create)').trigger('click'); + var $newevent = calendar.$('.fc-event:contains(new event)'); + + assert.strictEqual($newevent.text().replace(/[\s\n\r]+/g, ''), "8:00am-10:00amnewevent12/13/201608:00:00False", + "should display the new event with time, title and additional fields"); + + assert.deepEqual($newevent.data('fcSeg').event.record, + { + display_name: "new event", + start: fieldUtils.parse.datetime("2016-12-13 06:00:00", this.data.event.fields.start, {isUTC: true}), + stop: fieldUtils.parse.datetime("2016-12-13 08:00:00", this.data.event.fields.stop, {isUTC: true}), + allday: false, + name: "new event", + id: 1 + }, + "the new record should have the utc datetime (quickCreate)"); + + // delete record + + $newevent.trigger('click'); + $('.modal button.btn-default:contains(Delete)').trigger('click'); + $('.modal button.btn-primary:contains(Ok)').trigger('click'); + assert.strictEqual(calendar.$('.fc-content').length, 0, "should delete the record"); + + calendar.destroy(); + $view.remove(); + }); + + QUnit.test('create event with timezone in week mode with formViewDialog American locale', function (assert) { + assert.expect(8); + + this.data.event.records = []; + this.data.event.onchanges = { + allday: function (obj) { + if (obj.allday) { + obj.start_date = obj.start && obj.start.split(' ')[0] || obj.start_date; + obj.stop_date = obj.stop && obj.stop.split(' ')[0] || obj.stop_date || obj.start_date; + } else { + obj.start = obj.start_date && (obj.start_date + ' 00:00:00') || obj.start; + obj.stop = obj.stop_date && (obj.stop_date + ' 00:00:00') || obj.stop || obj.start; + } + } + }; + + var calendar = createView({ + View: CalendarView, + model: 'event', + data: this.data, + arch: + '<calendar class="o_calendar_test" '+ + 'event_open_popup="true" '+ + 'date_start="start" '+ + 'date_stop="stop" '+ + 'all_day="allday" '+ + 'mode="week" '+ + 'readonly_form_view_id="1">'+ + '<field name="name"/>'+ + '</calendar>', + archs: archs, + viewOptions: { + initialDate: initialDate, + }, + session: { + getTZOffset: function () { + return 120; + }, + }, + translateParameters: { // Avoid issues due to localization formats + time_format: "%I:%M:%S", + }, + mockRPC: function (route, args) { + if (args.method === "create") { + assert.deepEqual(args.kwargs.context, { + "default_name": "new event", + "default_start": "2016-12-13 06:00:00", + "default_stop": "2016-12-13 08:00:00", + "default_allday": null + }, + "should send the context to create events"); + } + if (args.method === "write") { + assert.deepEqual(args.args[1], expectedEvent, + "should move the event"); + } + return this._super(route, args); + }, + }); + + var $view = $('#qunit-fixture').contents(); + $view.prependTo('body'); // => select with click position + + var top = calendar.$('.fc-axis:contains(8am)').offset().top + 5; + var left = calendar.$('.fc-day:eq(2)').offset().left + 5; + + try { + testUtils.triggerPositionalMouseEvent(left, top, "mousedown"); + } catch (e) { + calendar.destroy(); + $view.remove(); + throw new Error('The test fails to simulate a click in the screen. Your screen is probably too small or your dev tools is open.'); + } + testUtils.triggerPositionalMouseEvent(left, top + 60, "mousemove"); + testUtils.triggerPositionalMouseEvent(left, top + 60, "mouseup"); + $('.modal input:first').val('new event').trigger('input'); + $('.modal button.btn:contains(Edit)').trigger('click'); + + assert.strictEqual($('.o_field_widget[name="start"] input').val(), "12/13/2016 08:00:00", + "should display the datetime"); + + $('.modal-lg .o_field_boolean[name="allday"] input').trigger('click'); + + assert.strictEqual($('.o_field_widget[name="start_date"] input').val(), "12/13/2016", + "should display the date"); + + $('.modal-lg .o_field_boolean[name="allday"] input').trigger('click'); + + assert.strictEqual($('.o_field_widget[name="start"] input').val(), "12/13/2016 02:00:00", + "should display the datetime from the date with the timezone"); + + // use datepicker to enter a date: 12/13/2016 08:00:00 + $('.o_field_widget[name="start"] input').trigger('click'); + $('.bootstrap-datetimepicker-widget .picker-switch a[data-action="togglePicker"]').trigger('click'); + $('.bootstrap-datetimepicker-widget .timepicker .timepicker-hour').trigger('click'); + $('.bootstrap-datetimepicker-widget .timepicker-hours td.hour:contains(08)').trigger('click'); + $('.bootstrap-datetimepicker-widget .picker-switch a[data-action="close"]').trigger('click'); + + // use datepicker to enter a date: 12/13/2016 10:00:00 + $('.o_field_widget[name="stop"] input').trigger('click'); + $('.bootstrap-datetimepicker-widget .picker-switch a[data-action="togglePicker"]').trigger('click'); + $('.bootstrap-datetimepicker-widget .timepicker .timepicker-hour').trigger('click'); + $('.bootstrap-datetimepicker-widget .timepicker-hours td.hour:contains(10)').trigger('click'); + $('.bootstrap-datetimepicker-widget .picker-switch a[data-action="close"]').trigger('click'); + + $('.modal-lg button.btn:contains(Save)').trigger('click'); + var $newevent = calendar.$('.fc-event:contains(new event)'); + + assert.strictEqual($newevent.text().replace(/[\s\n\r]+/g, ''), "8:00am-10:00amnewevent", + "should display the new event with time and title"); + + assert.deepEqual($newevent.data('fcSeg').event.record, + { + display_name: "new event", + start: fieldUtils.parse.datetime("2016-12-13 06:00:00", this.data.event.fields.start, {isUTC: true}), + stop: fieldUtils.parse.datetime("2016-12-13 08:00:00", this.data.event.fields.stop, {isUTC: true}), + allday: false, + name: "new event", + id: 1 + }, + "the new record should have the utc datetime (formViewDialog)"); + + var pos = calendar.$('.fc-content').offset(); + left = pos.left + 5; + top = pos.top + 5; + + // Mode this event to another day + var expectedEvent = { + "allday": false, + "start": "2016-12-12 06:00:00", + "stop": "2016-12-12 08:00:00" + }; + testUtils.triggerPositionalMouseEvent(left, top, "mousedown"); + left = calendar.$('.fc-day:eq(1)').offset().left + 5; + testUtils.triggerPositionalMouseEvent(left, top, "mousemove"); + testUtils.triggerPositionalMouseEvent(left, top, "mouseup"); + + // Move to "All day" + expectedEvent = { + "allday": true, + "start": "2016-12-12 00:00:00", + "stop": "2016-12-12 00:00:00" + }; + testUtils.triggerPositionalMouseEvent(left, top, "mousedown"); + top = calendar.$('.fc-day:eq(1)').offset().top + 5; + testUtils.triggerPositionalMouseEvent(left, top, "mousemove"); + testUtils.triggerPositionalMouseEvent(left, top, "mouseup"); + + calendar.destroy(); + $view.remove(); + }); + + QUnit.test('check calendar week column timeformat and event content timeformat', function (assert) { + assert.expect(2); + + var calendar = createView({ + View: CalendarView, + model: 'event', + data: this.data, + arch: + '<calendar date_start="start">'+ + '<field name="name"/>'+ + '</calendar>', + archs: archs, + viewOptions: { + initialDate: initialDate, + }, + translateParameters: { + time_format: "%I:%M:%S", + }, + }); + + assert.strictEqual(calendar.$('.fc-axis:contains(8am)').length, 1, "calendar should show according to timeformat"); + assert.strictEqual(calendar.$('.fc-event:first:contains(12:00am)').length, 1, + "event time format should 12 hour"); + + calendar.destroy(); + }); + QUnit.test('create all day event in week mode', function (assert) { assert.expect(3); @@ -1601,12 +1883,15 @@ QUnit.module('Views', { viewOptions: { initialDate: initialDate, }, + translateParameters: { // Avoid issues due to localization formats + time_format: "%H:%M:%S", + }, }); // Click on Tuesday 12am var $view = $('#qunit-fixture').contents(); $view.prependTo('body'); - var top = calendar.$('.fc-axis:contains(12am)').offset().top + 5; + var top = calendar.$('.fc-axis:contains(0:00)').offset().top + 5; var left = calendar.$('.fc-day:eq(2)').offset().left + 5; try { testUtils.triggerPositionalMouseEvent(left, top, "mousedown");