[REF] web: refactor the calendar view
Improve design and introducing several usability improvements:
- Removed customization of an event card, just display event title.
- Added popover, popover consist of two sections:
1) Show the title, date and time of an event. Date and time are
automatically computed according to the user timing preferences,
language and event duration. Can be hidden with hide_date/hide_time
attribute respectively.
2) Display all the fields specified inside the <calendar/> element.
fields can be specified with a widget and its options.
e.g. <field name="name" string="Custom Name" widget="char" options="{}"/>
- Show avatar in popover for filters.
- Removed hide sidebar feature.
- Increase readability using a better color selection.
- Better UI in mobile.
And, Adapted test cases
Task 1919926
Co-authored-by: jat-odoo <jat@openerp.com>
This commit is contained in:
committed by
Jigar Patel
co-authored by
jat-odoo
parent
aca0e700ac
commit
369c20a99b
@@ -27,13 +27,13 @@ var CalendarController = AbstractController.extend({
|
|||||||
custom_events: _.extend({}, AbstractController.prototype.custom_events, {
|
custom_events: _.extend({}, AbstractController.prototype.custom_events, {
|
||||||
changeDate: '_onChangeDate',
|
changeDate: '_onChangeDate',
|
||||||
changeFilter: '_onChangeFilter',
|
changeFilter: '_onChangeFilter',
|
||||||
|
deleteRecord: '_onDeleteRecord',
|
||||||
dropRecord: '_onDropRecord',
|
dropRecord: '_onDropRecord',
|
||||||
next: '_onNext',
|
next: '_onNext',
|
||||||
openCreate: '_onOpenCreate',
|
openCreate: '_onOpenCreate',
|
||||||
openEvent: '_onOpenEvent',
|
openEvent: '_onOpenEvent',
|
||||||
prev: '_onPrev',
|
prev: '_onPrev',
|
||||||
quickCreate: '_onQuickCreate',
|
quickCreate: '_onQuickCreate',
|
||||||
toggleFullWidth: '_onToggleFullWidth',
|
|
||||||
updateRecord: '_onUpdateRecord',
|
updateRecord: '_onUpdateRecord',
|
||||||
viewUpdated: '_onViewUpdated',
|
viewUpdated: '_onViewUpdated',
|
||||||
}),
|
}),
|
||||||
@@ -200,6 +200,20 @@ var CalendarController = AbstractController.extend({
|
|||||||
this.reload();
|
this.reload();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
* @param {OdooEvent} event
|
||||||
|
*/
|
||||||
|
_onDeleteRecord: function (event) {
|
||||||
|
var self = this;
|
||||||
|
Dialog.confirm(this, _t("Are you sure you want to delete this record ?"), {
|
||||||
|
confirm_callback: function () {
|
||||||
|
self.model.deleteRecords([event.data.id], self.modelName).then(function () {
|
||||||
|
self.reload();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
/**
|
/**
|
||||||
* @private
|
* @private
|
||||||
* @param {OdooEvent} event
|
* @param {OdooEvent} event
|
||||||
@@ -323,53 +337,22 @@ var CalendarController = AbstractController.extend({
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var open_dialog = function (readonly) {
|
var options = {
|
||||||
var options = {
|
res_model: self.modelName,
|
||||||
res_model: self.modelName,
|
res_id: id || null,
|
||||||
res_id: id || null,
|
context: event.context || self.context,
|
||||||
context: event.context || self.context,
|
title: _t("Open: ") + event.data.title,
|
||||||
readonly: readonly,
|
on_saved: function () {
|
||||||
title: _t("Open: ") + event.data.title,
|
if (event.data.on_save) {
|
||||||
on_saved: function () {
|
event.data.on_save();
|
||||||
if (event.data.on_save) {
|
|
||||||
event.data.on_save();
|
|
||||||
}
|
|
||||||
self.reload();
|
|
||||||
},
|
|
||||||
};
|
|
||||||
if (readonly) {
|
|
||||||
if (self.readonlyFormViewId) {
|
|
||||||
options.view_id = parseInt(self.readonlyFormViewId);
|
|
||||||
}
|
}
|
||||||
options.buttons = [
|
self.reload();
|
||||||
{
|
},
|
||||||
text: _t("Edit"),
|
|
||||||
classes: 'btn-primary',
|
|
||||||
close: true,
|
|
||||||
click: function () { open_dialog(false); }
|
|
||||||
},
|
|
||||||
{
|
|
||||||
text: _t("Delete"),
|
|
||||||
click: function () {
|
|
||||||
Dialog.confirm(this, _t("Are you sure you want to delete this record ?"), {
|
|
||||||
confirm_callback: function () {
|
|
||||||
self.model.deleteRecords([id], self.modelName)
|
|
||||||
.then(function () {
|
|
||||||
self.dialog.destroy();
|
|
||||||
self.reload();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{text: _t("Close"), close: true}
|
|
||||||
];
|
|
||||||
} else if (self.formViewId) {
|
|
||||||
options.view_id = parseInt(self.formViewId);
|
|
||||||
}
|
|
||||||
self.dialog = new dialogs.FormViewDialog(self, options).open();
|
|
||||||
};
|
};
|
||||||
open_dialog(true);
|
if (this.formViewId) {
|
||||||
|
options.view_id = parseInt(this.formViewId);
|
||||||
|
}
|
||||||
|
new dialogs.FormViewDialog(this, options).open();
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
* @private
|
* @private
|
||||||
@@ -410,15 +393,6 @@ var CalendarController = AbstractController.extend({
|
|||||||
self.quickCreating = false;
|
self.quickCreating = false;
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
/**
|
|
||||||
* Called when we want to open or close the sidebar.
|
|
||||||
*
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
_onToggleFullWidth: function () {
|
|
||||||
this.model.toggleFullWidth();
|
|
||||||
this.reload();
|
|
||||||
},
|
|
||||||
/**
|
/**
|
||||||
* @private
|
* @private
|
||||||
* @param {OdooEvent} event
|
* @param {OdooEvent} event
|
||||||
|
|||||||
@@ -308,13 +308,6 @@ return AbstractModel.extend({
|
|||||||
today: function () {
|
today: function () {
|
||||||
this.setDate(moment(new Date()));
|
this.setDate(moment(new Date()));
|
||||||
},
|
},
|
||||||
/**
|
|
||||||
* Toggle the sidebar (containing the mini calendar)
|
|
||||||
*/
|
|
||||||
toggleFullWidth: function () {
|
|
||||||
var fullWidth = this.call('local_storage', 'getItem', 'calendar_fullWidth') !== true;
|
|
||||||
this.call('local_storage', 'setItem', 'calendar_fullWidth', fullWidth);
|
|
||||||
},
|
|
||||||
/**
|
/**
|
||||||
* @param {Object} record
|
* @param {Object} record
|
||||||
* @param {integer} record.id
|
* @param {integer} record.id
|
||||||
@@ -410,8 +403,10 @@ return AbstractModel.extend({
|
|||||||
snapMinutes: 15,
|
snapMinutes: 15,
|
||||||
longPressDelay: 500,
|
longPressDelay: 500,
|
||||||
eventResizableFromStart: true,
|
eventResizableFromStart: true,
|
||||||
|
nowIndicator: true,
|
||||||
weekNumbers: true,
|
weekNumbers: true,
|
||||||
weekNumberTitle: _t("W"),
|
weekNumbersWithinDays: true,
|
||||||
|
weekNumberTitle: _t("Week") + " ",
|
||||||
allDayText: _t("All day"),
|
allDayText: _t("All day"),
|
||||||
monthNames: moment.months(),
|
monthNames: moment.months(),
|
||||||
monthNamesShort: moment.monthsShort(),
|
monthNamesShort: moment.monthsShort(),
|
||||||
@@ -444,7 +439,6 @@ return AbstractModel.extend({
|
|||||||
*/
|
*/
|
||||||
_loadCalendar: function () {
|
_loadCalendar: function () {
|
||||||
var self = this;
|
var self = this;
|
||||||
this.data.fullWidth = this.call('local_storage', 'getItem', 'calendar_fullWidth') === true;
|
|
||||||
this.data.fc_options = this._getFullCalendarOptions();
|
this.data.fc_options = this._getFullCalendarOptions();
|
||||||
|
|
||||||
var defs = _.map(this.data.filters, this._loadFilter.bind(this));
|
var defs = _.map(this.data.filters, this._loadFilter.bind(this));
|
||||||
|
|||||||
@@ -0,0 +1,140 @@
|
|||||||
|
odoo.define('web.CalendarPopover', function (require) {
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
var fieldRegistry = require('web.field_registry');
|
||||||
|
var StandaloneFieldManagerMixin = require('web.StandaloneFieldManagerMixin');
|
||||||
|
var Widget = require('web.Widget');
|
||||||
|
|
||||||
|
var CalendarPopover = Widget.extend(StandaloneFieldManagerMixin, {
|
||||||
|
template: 'CalendarView.event.popover',
|
||||||
|
events: {
|
||||||
|
'click .o_cw_popover_edit': '_onClickPopoverEdit',
|
||||||
|
'click .o_cw_popover_delete': '_onClickPopoverDelete',
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* @constructor
|
||||||
|
* @param {Widget} parent
|
||||||
|
* @param {Object} eventInfo
|
||||||
|
*/
|
||||||
|
init: function (parent, eventInfo) {
|
||||||
|
this._super.apply(this, arguments);
|
||||||
|
StandaloneFieldManagerMixin.init.call(this);
|
||||||
|
this.hideDate = eventInfo.hideDate;
|
||||||
|
this.hideTime = eventInfo.hideTime;
|
||||||
|
this.eventTime = eventInfo.eventTime;
|
||||||
|
this.eventDate = eventInfo.eventDate;
|
||||||
|
this.displayFields = eventInfo.displayFields;
|
||||||
|
this.fields = eventInfo.fields;
|
||||||
|
this.event = eventInfo.event;
|
||||||
|
this.modelName = eventInfo.modelName;
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* @override
|
||||||
|
*/
|
||||||
|
willStart: function () {
|
||||||
|
return Promise.all([this._super.apply(this, arguments), this._processFields()]);
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* @override
|
||||||
|
*/
|
||||||
|
start: function () {
|
||||||
|
var self = this;
|
||||||
|
_.each(this.$fieldsList, function ($field) {
|
||||||
|
$field.appendTo(self.$('.o_cw_popover_fields_secondary'));
|
||||||
|
});
|
||||||
|
return this._super.apply(this, arguments);
|
||||||
|
},
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------
|
||||||
|
// Private
|
||||||
|
//--------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate fields to render into popover
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
* @returns {Promise}
|
||||||
|
*/
|
||||||
|
_processFields: function () {
|
||||||
|
var self = this;
|
||||||
|
var fieldsToGenerate = [];
|
||||||
|
_.each(this.displayFields, function (displayFieldInfo, fieldName) {
|
||||||
|
var fieldInfo = self.fields[fieldName];
|
||||||
|
var field = {
|
||||||
|
name: fieldName,
|
||||||
|
string: displayFieldInfo.attrs.string || fieldInfo.string,
|
||||||
|
value: self.event.record[fieldName],
|
||||||
|
type: fieldInfo.type,
|
||||||
|
};
|
||||||
|
if (field.type === 'selection') {
|
||||||
|
field.selection = fieldInfo.selection;
|
||||||
|
}
|
||||||
|
if (fieldInfo.relation) {
|
||||||
|
field.relation = fieldInfo.relation;
|
||||||
|
}
|
||||||
|
if (displayFieldInfo.attrs.widget) {
|
||||||
|
field.widget = displayFieldInfo.attrs.widget;
|
||||||
|
} else if (_.contains(['many2many', 'one2many'], field.type)) {
|
||||||
|
field.widget = 'many2many_tags';
|
||||||
|
}
|
||||||
|
if (_.contains(['many2many', 'one2many'], field.type)) {
|
||||||
|
field.fields = [{
|
||||||
|
name: 'id',
|
||||||
|
type: 'integer',
|
||||||
|
}, {
|
||||||
|
name: 'display_name',
|
||||||
|
type: 'char',
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
fieldsToGenerate.push(field);
|
||||||
|
});
|
||||||
|
|
||||||
|
this.$fieldsList = [];
|
||||||
|
return this.model.makeRecord(this.modelName, fieldsToGenerate).then(function (recordID) {
|
||||||
|
var defs = [];
|
||||||
|
|
||||||
|
var record = self.model.get(recordID);
|
||||||
|
_.each(fieldsToGenerate, function (field) {
|
||||||
|
var FieldClass = fieldRegistry.getAny([field.widget, field.type]);
|
||||||
|
var fieldWidget = new FieldClass(self, field.name, record, self.displayFields[field.name]);
|
||||||
|
self._registerWidget(recordID, field.name, fieldWidget);
|
||||||
|
|
||||||
|
var $field = $('<li>', {class: 'list-group-item flex-shrink-0 d-flex flex-wrap'});
|
||||||
|
var $fieldLabel = $('<strong>', {class: 'mr-2', text: _.str.sprintf('%s : ', field.string)});
|
||||||
|
$fieldLabel.appendTo($field);
|
||||||
|
var $fieldContainer = $('<div>', {class: 'flex-grow-1'});
|
||||||
|
$fieldContainer.appendTo($field);
|
||||||
|
|
||||||
|
defs.push(fieldWidget.appendTo($fieldContainer).then(function () {
|
||||||
|
self.$fieldsList.push($field);
|
||||||
|
}));
|
||||||
|
});
|
||||||
|
return Promise.all(defs);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------
|
||||||
|
// Handlers
|
||||||
|
//--------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
* @param {jQueryEvent} ev
|
||||||
|
*/
|
||||||
|
_onClickPopoverEdit: function (ev) {
|
||||||
|
ev.preventDefault();
|
||||||
|
this.trigger_up('edit_event', {id: this.event.id});
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
* @param {jQueryEvent} ev
|
||||||
|
*/
|
||||||
|
_onClickPopoverDelete: function (ev) {
|
||||||
|
ev.preventDefault();
|
||||||
|
this.trigger_up('delete_event', {id: this.event.id});
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
return CalendarPopover;
|
||||||
|
|
||||||
|
});
|
||||||
@@ -2,15 +2,14 @@ odoo.define('web.CalendarRenderer', function (require) {
|
|||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
var AbstractRenderer = require('web.AbstractRenderer');
|
var AbstractRenderer = require('web.AbstractRenderer');
|
||||||
|
var CalendarPopover = require('web.CalendarPopover');
|
||||||
var config = require('web.config');
|
var config = require('web.config');
|
||||||
var core = require('web.core');
|
var core = require('web.core');
|
||||||
var Dialog = require('web.Dialog');
|
var Dialog = require('web.Dialog');
|
||||||
var field_utils = require('web.field_utils');
|
var field_utils = require('web.field_utils');
|
||||||
var FieldManagerMixin = require('web.FieldManagerMixin');
|
var FieldManagerMixin = require('web.FieldManagerMixin');
|
||||||
var QWeb = require('web.QWeb');
|
|
||||||
var relational_fields = require('web.relational_fields');
|
var relational_fields = require('web.relational_fields');
|
||||||
var session = require('web.session');
|
var session = require('web.session');
|
||||||
var utils = require('web.utils');
|
|
||||||
var Widget = require('web.Widget');
|
var Widget = require('web.Widget');
|
||||||
|
|
||||||
var _t = core._t;
|
var _t = core._t;
|
||||||
@@ -78,7 +77,7 @@ var SidebarFilter = Widget.extend(FieldManagerMixin, {
|
|||||||
{
|
{
|
||||||
mode: 'edit',
|
mode: 'edit',
|
||||||
attrs: {
|
attrs: {
|
||||||
placeholder: _.str.sprintf(_t("Add %s"), self.title),
|
placeholder: "+ " + _.str.sprintf(_t("Add %s"), self.title),
|
||||||
can_create: false
|
can_create: false
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
@@ -98,7 +97,7 @@ var SidebarFilter = Widget.extend(FieldManagerMixin, {
|
|||||||
this.many2one.filter_ids = _.without(_.pluck(this.filters, 'value'), 'all');
|
this.many2one.filter_ids = _.without(_.pluck(this.filters, 'value'), 'all');
|
||||||
}
|
}
|
||||||
this.$el.on('click', '.o_remove', this._onFilterRemove.bind(this));
|
this.$el.on('click', '.o_remove', this._onFilterRemove.bind(this));
|
||||||
this.$el.on('click', '.custom-checkbox input', this._onFilterActive.bind(this));
|
this.$el.on('click', '.o_calendar_filter_items input', this._onFilterActive.bind(this));
|
||||||
},
|
},
|
||||||
|
|
||||||
//--------------------------------------------------------------------------
|
//--------------------------------------------------------------------------
|
||||||
@@ -169,8 +168,12 @@ var SidebarFilter = Widget.extend(FieldManagerMixin, {
|
|||||||
|
|
||||||
return AbstractRenderer.extend({
|
return AbstractRenderer.extend({
|
||||||
template: "CalendarView",
|
template: "CalendarView",
|
||||||
events: _.extend({}, AbstractRenderer.prototype.events, {
|
config: {
|
||||||
'click .o_calendar_sidebar_toggler': '_onToggleSidebar',
|
CalendarPopover: CalendarPopover,
|
||||||
|
},
|
||||||
|
custom_events: _.extend({}, AbstractRenderer.prototype.custom_events || {}, {
|
||||||
|
edit_event: '_onEditEvent',
|
||||||
|
delete_event: '_onDeleteEvent',
|
||||||
}),
|
}),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -185,11 +188,8 @@ return AbstractRenderer.extend({
|
|||||||
this.model = params.model;
|
this.model = params.model;
|
||||||
this.filters = [];
|
this.filters = [];
|
||||||
this.color_map = {};
|
this.color_map = {};
|
||||||
|
this.hideDate = params.hideDate;
|
||||||
if (params.eventTemplate) {
|
this.hideTime = params.hideTime;
|
||||||
this.qweb = new QWeb(config.isDebug(), {_s: session.origin});
|
|
||||||
this.qweb.add_template(utils.json_node_to_xml(params.eventTemplate));
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
* @override
|
* @override
|
||||||
@@ -203,6 +203,20 @@ return AbstractRenderer.extend({
|
|||||||
}
|
}
|
||||||
return this._super();
|
return this._super();
|
||||||
},
|
},
|
||||||
|
/**
|
||||||
|
* @override
|
||||||
|
*/
|
||||||
|
on_attach_callback: function () {
|
||||||
|
if (config.device.isMobile) {
|
||||||
|
this.$el.height($(window).height() - this.$el.offset().top);
|
||||||
|
}
|
||||||
|
var scrollTop = this.$calendar.find('.fc-scroller').scrollTop();
|
||||||
|
if (scrollTop) {
|
||||||
|
this.$calendar.fullCalendar('reinitView');
|
||||||
|
} else {
|
||||||
|
this.$calendar.fullCalendar('render');
|
||||||
|
}
|
||||||
|
},
|
||||||
/**
|
/**
|
||||||
* @override
|
* @override
|
||||||
*/
|
*/
|
||||||
@@ -325,19 +339,14 @@ return AbstractRenderer.extend({
|
|||||||
_eventRender: function (event) {
|
_eventRender: function (event) {
|
||||||
var qweb_context = {
|
var qweb_context = {
|
||||||
event: event,
|
event: event,
|
||||||
fields: this.state.fields,
|
|
||||||
format: this._format.bind(this),
|
|
||||||
isMobile: config.device.isMobile,
|
|
||||||
read_only_mode: this.read_only_mode,
|
|
||||||
record: event.record,
|
record: event.record,
|
||||||
user_context: session.user_context,
|
color: this.getColor(event.color_index),
|
||||||
widget: this,
|
|
||||||
};
|
};
|
||||||
this.qweb_context = qweb_context;
|
this.qweb_context = qweb_context;
|
||||||
if (_.isEmpty(qweb_context.record)) {
|
if (_.isEmpty(qweb_context.record)) {
|
||||||
return '';
|
return '';
|
||||||
} else {
|
} else {
|
||||||
return (this.qweb || qweb).render("calendar-box", qweb_context);
|
return qweb.render("calendar-box", qweb_context);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
@@ -375,40 +384,54 @@ return AbstractRenderer.extend({
|
|||||||
self.trigger_up('dropRecord', event);
|
self.trigger_up('dropRecord', event);
|
||||||
},
|
},
|
||||||
eventResize: function (event) {
|
eventResize: function (event) {
|
||||||
|
self._unselectEvent();
|
||||||
self.trigger_up('updateRecord', event);
|
self.trigger_up('updateRecord', event);
|
||||||
},
|
},
|
||||||
eventClick: function (event) {
|
eventClick: function (eventData, ev) {
|
||||||
self.trigger_up('openEvent', event);
|
self._unselectEvent();
|
||||||
self.$calendar.fullCalendar('unselect');
|
self.$calendar.find(_.str.sprintf('[data-event-id=%s]', eventData.id)).addClass('o_cw_custom_highlight');
|
||||||
|
self._renderEventPopover(eventData, $(ev.currentTarget));
|
||||||
},
|
},
|
||||||
select: function (target_date, end_date, event, _js_event, _view) {
|
select: function (startDate, endDate) {
|
||||||
var data = {'start': target_date, 'end': end_date};
|
// Clicking on the view, dispose any visible popover. Otherwise create a new event.
|
||||||
if (self.state.context.default_name) {
|
if (self.$('.o_cw_popover').length) {
|
||||||
data.title = self.state.context.default_name;
|
self._unselectEvent();
|
||||||
|
} else {
|
||||||
|
var data = {start: startDate, end: endDate};
|
||||||
|
if (self.state.context.default_name) {
|
||||||
|
data.title = self.state.context.default_name;
|
||||||
|
}
|
||||||
|
self.trigger_up('openCreate', data);
|
||||||
}
|
}
|
||||||
self.trigger_up('openCreate', data);
|
|
||||||
self.$calendar.fullCalendar('unselect');
|
self.$calendar.fullCalendar('unselect');
|
||||||
},
|
},
|
||||||
eventRender: function (event, element) {
|
eventRender: function (event, element, view) {
|
||||||
var $render = $(self._eventRender(event));
|
var $render = $(self._eventRender(event));
|
||||||
event.title = $render.find('.o_field_type_char:first').text();
|
|
||||||
element.find('.fc-content').html($render.html());
|
element.find('.fc-content').html($render.html());
|
||||||
element.addClass($render.attr('class'));
|
element.addClass($render.attr('class'));
|
||||||
var display_hour = '';
|
element.attr('data-event-id', event.id);
|
||||||
if (!event.allDay) {
|
|
||||||
|
// Add background if doesn't exist
|
||||||
|
if (!element.find('.fc-bg').length) {
|
||||||
|
element.find('.fc-content').after($('<div/>', {class: 'fc-bg'}));
|
||||||
|
}
|
||||||
|
|
||||||
|
// For month view: Show background for all-day/multidate events only
|
||||||
|
if (view.name === 'month' && event.record) {
|
||||||
var start = event.r_start || event.start;
|
var start = event.r_start || event.start;
|
||||||
var end = event.r_end || event.end;
|
var end = event.r_end || event.end;
|
||||||
var timeFormat = _t.database.parameters.time_format.search("%H") != -1 ? 'HH:mm': 'h:mma';
|
// Detect if the event occurs in just one day
|
||||||
display_hour = start.format(timeFormat) + ' - ' + end.format(timeFormat);
|
// note: add & remove 1 min to avoid issues with 00:00
|
||||||
if (display_hour === '00:00 - 00:00') {
|
var isSameDayEvent = start.clone().add(1, 'minute').isSame(end.clone().subtract(1, 'minute'), 'day');
|
||||||
display_hour = _t('All day');
|
if (!event.record.allday && isSameDayEvent) {
|
||||||
|
element.addClass('o_cw_nobg');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
element.find('.fc-content .fc-time').text(display_hour);
|
|
||||||
},
|
// On double click, edit the event
|
||||||
// Dirty hack to ensure a correct first render
|
element.on('dblclick', function () {
|
||||||
eventAfterAllRender: function () {
|
self.trigger_up('edit_event', {id: event.id});
|
||||||
$(window).trigger('resize');
|
});
|
||||||
},
|
},
|
||||||
viewRender: function (view) {
|
viewRender: function (view) {
|
||||||
// compute mode from view.name which is either 'month', 'agendaWeek' or 'agendaDay'
|
// compute mode from view.name which is either 'month', 'agendaWeek' or 'agendaDay'
|
||||||
@@ -418,6 +441,39 @@ return AbstractRenderer.extend({
|
|||||||
title: view.title,
|
title: view.title,
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
// Add/Remove a class on hover to style multiple days events.
|
||||||
|
// The css ":hover" selector can't be used because these events
|
||||||
|
// are rendered using multiple elements.
|
||||||
|
eventMouseover: function (eventData) {
|
||||||
|
self.$calendar.find(_.str.sprintf('[data-event-id=%s]', eventData.id)).addClass('o_cw_custom_hover');
|
||||||
|
},
|
||||||
|
eventMouseout: function (eventData) {
|
||||||
|
self.$calendar.find(_.str.sprintf('[data-event-id=%s]', eventData.id)).removeClass('o_cw_custom_hover');
|
||||||
|
},
|
||||||
|
eventDragStart: function () {
|
||||||
|
self._unselectEvent();
|
||||||
|
},
|
||||||
|
eventResizeStart: function () {
|
||||||
|
self._unselectEvent();
|
||||||
|
},
|
||||||
|
eventLimitClick: function () {
|
||||||
|
self._unselectEvent();
|
||||||
|
return 'popover';
|
||||||
|
},
|
||||||
|
windowResize: function () {
|
||||||
|
self._render();
|
||||||
|
},
|
||||||
|
views: {
|
||||||
|
day: {
|
||||||
|
columnFormat: 'LL'
|
||||||
|
},
|
||||||
|
week: {
|
||||||
|
columnFormat: 'ddd D'
|
||||||
|
},
|
||||||
|
month: {
|
||||||
|
columnFormat: config.device.isMobile ? 'ddd' : 'dddd'
|
||||||
|
}
|
||||||
|
},
|
||||||
height: 'parent',
|
height: 'parent',
|
||||||
unselectAuto: false,
|
unselectAuto: false,
|
||||||
isRTL: _t.database.parameters.direction === "rtl",
|
isRTL: _t.database.parameters.direction === "rtl",
|
||||||
@@ -440,6 +496,7 @@ return AbstractRenderer.extend({
|
|||||||
date: moment(new Date(+obj.currentYear , +obj.currentMonth, +obj.currentDay))
|
date: moment(new Date(+obj.currentYear , +obj.currentMonth, +obj.currentDay))
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
'showOtherMonths': true,
|
||||||
'dayNamesMin' : this.state.fc_options.dayNamesShort,
|
'dayNamesMin' : this.state.fc_options.dayNamesShort,
|
||||||
'monthNames': this.state.fc_options.monthNamesShort,
|
'monthNames': this.state.fc_options.monthNamesShort,
|
||||||
'firstDay': this.state.fc_options.firstDay,
|
'firstDay': this.state.fc_options.firstDay,
|
||||||
@@ -466,7 +523,6 @@ return AbstractRenderer.extend({
|
|||||||
var $calendar = this.$calendar;
|
var $calendar = this.$calendar;
|
||||||
var $fc_view = $calendar.find('.fc-view');
|
var $fc_view = $calendar.find('.fc-view');
|
||||||
var scrollPosition = $fc_view.scrollLeft();
|
var scrollPosition = $fc_view.scrollLeft();
|
||||||
var scrollTop = this.$calendar.find('.fc-scroller').scrollTop();
|
|
||||||
|
|
||||||
$fc_view.scrollLeft(0);
|
$fc_view.scrollLeft(0);
|
||||||
$calendar.fullCalendar('unselect');
|
$calendar.fullCalendar('unselect');
|
||||||
@@ -485,8 +541,8 @@ return AbstractRenderer.extend({
|
|||||||
.removeClass('o_color o_selected_range');
|
.removeClass('o_color o_selected_range');
|
||||||
var $a;
|
var $a;
|
||||||
switch (this.state.scale) {
|
switch (this.state.scale) {
|
||||||
case 'month': $a = this.$small_calendar.find('td a'); break;
|
case 'month': $a = this.$small_calendar.find('td'); break;
|
||||||
case 'week': $a = this.$small_calendar.find('tr:has(.ui-state-active) a'); break;
|
case 'week': $a = this.$small_calendar.find('tr:has(.ui-state-active)'); break;
|
||||||
case 'day': $a = this.$small_calendar.find('a.ui-state-active'); break;
|
case 'day': $a = this.$small_calendar.find('a.ui-state-active'); break;
|
||||||
}
|
}
|
||||||
$a.addClass('o_selected_range');
|
$a.addClass('o_selected_range');
|
||||||
@@ -496,21 +552,8 @@ return AbstractRenderer.extend({
|
|||||||
|
|
||||||
$fc_view.scrollLeft(scrollPosition);
|
$fc_view.scrollLeft(scrollPosition);
|
||||||
|
|
||||||
var fullWidth = this.state.fullWidth;
|
this._unselectEvent();
|
||||||
this.$('.o_calendar_sidebar_toggler')
|
|
||||||
.toggleClass('fa-close', !fullWidth)
|
|
||||||
.toggleClass('fa-chevron-left', fullWidth)
|
|
||||||
.attr('title', !fullWidth ? _('Close Sidebar') : _('Open Sidebar'));
|
|
||||||
this.$sidebar_container.toggleClass('o_sidebar_hidden', fullWidth);
|
|
||||||
this.$sidebar.toggleClass('o_hidden', fullWidth);
|
|
||||||
|
|
||||||
var filterProm = this._renderFilters();
|
var filterProm = this._renderFilters();
|
||||||
this.$calendar.appendTo('body');
|
|
||||||
if (scrollTop) {
|
|
||||||
this.$calendar.fullCalendar('reinitView');
|
|
||||||
} else {
|
|
||||||
this.$calendar.fullCalendar('render');
|
|
||||||
}
|
|
||||||
this._renderEvents();
|
this._renderEvents();
|
||||||
this.$calendar.prependTo(this.$('.o_calendar_view'));
|
this.$calendar.prependTo(this.$('.o_calendar_view'));
|
||||||
|
|
||||||
@@ -532,6 +575,8 @@ return AbstractRenderer.extend({
|
|||||||
* @returns {Promise} resolved when all filters have been rendered
|
* @returns {Promise} resolved when all filters have been rendered
|
||||||
*/
|
*/
|
||||||
_renderFilters: function () {
|
_renderFilters: function () {
|
||||||
|
// Dispose of filter popover
|
||||||
|
this.$('.o_calendar_filter_item').popover('dispose');
|
||||||
_.each(this.filters || (this.filters = []), function (filter) {
|
_.each(this.filters || (this.filters = []), function (filter) {
|
||||||
filter.destroy();
|
filter.destroy();
|
||||||
});
|
});
|
||||||
@@ -565,24 +610,152 @@ return AbstractRenderer.extend({
|
|||||||
options.fields = this.state.fields;
|
options.fields = this.state.fields;
|
||||||
var filter = new SidebarFilter(self, options);
|
var filter = new SidebarFilter(self, options);
|
||||||
prom = filter.appendTo(this.$sidebar).then(function () {
|
prom = filter.appendTo(this.$sidebar).then(function () {
|
||||||
|
// Show filter popover
|
||||||
|
if (options.avatar_field) {
|
||||||
|
_.each(options.filters, function (filter) {
|
||||||
|
if (filter.value !== 'all') {
|
||||||
|
var selector = _.str.sprintf('.o_calendar_filter_item[data-value=%s]', filter.value);
|
||||||
|
self.$sidebar.find(selector).popover({
|
||||||
|
animation: false,
|
||||||
|
trigger: 'hover',
|
||||||
|
html: true,
|
||||||
|
placement: 'top',
|
||||||
|
title: filter.label,
|
||||||
|
delay: {show: 300, hide: 0},
|
||||||
|
content: function () {
|
||||||
|
return $('<img>', {
|
||||||
|
src: _.str.sprintf('/web/image/%s/%s/%s', options.avatar_model, filter.value, options.avatar_field),
|
||||||
|
class: 'mx-auto',
|
||||||
|
});
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
return self._renderFiltersOneByOne(filterIndex + 1);
|
return self._renderFiltersOneByOne(filterIndex + 1);
|
||||||
});
|
});
|
||||||
this.filters.push(filter);
|
this.filters.push(filter);
|
||||||
}
|
}
|
||||||
return Promise.resolve(prom);
|
return Promise.resolve(prom);
|
||||||
},
|
},
|
||||||
|
/**
|
||||||
|
* Prepare context to display in the popover.
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
* @param {Object} eventData
|
||||||
|
* @returns {Object} context
|
||||||
|
*/
|
||||||
|
_getPopoverContext: function (eventData) {
|
||||||
|
var context = {
|
||||||
|
hideDate: this.hideDate,
|
||||||
|
hideTime: this.hideTime,
|
||||||
|
eventTime: {},
|
||||||
|
eventDate: {},
|
||||||
|
fields: this.state.fields,
|
||||||
|
displayFields: this.displayFields,
|
||||||
|
event: eventData,
|
||||||
|
modelName: this.model,
|
||||||
|
};
|
||||||
|
|
||||||
|
var start = moment(eventData.r_start || eventData.start);
|
||||||
|
var end = moment(eventData.r_end || eventData.end);
|
||||||
|
var isSameDayEvent = start.clone().add(1, 'minute').isSame(end.clone().subtract(1, 'minute'), 'day');
|
||||||
|
|
||||||
|
// Do not display timing if the event occur across multiple days. Otherwise use user's timing preferences
|
||||||
|
if (!this.hideTime && !eventData.record.allday && isSameDayEvent) {
|
||||||
|
// Fetch user's preferences
|
||||||
|
var dbTimeFormat = _t.database.parameters.time_format.search('%H') != -1 ? 'HH:mm': 'hh:mm a';
|
||||||
|
|
||||||
|
context.eventTime.time = start.clone().format(dbTimeFormat) + ' - ' + end.clone().format(dbTimeFormat);
|
||||||
|
|
||||||
|
// Calculate duration and format text
|
||||||
|
var durationHours = moment.duration(end.diff(start)).hours();
|
||||||
|
var durationHoursKey = (durationHours === 1) ? 'h' : 'hh';
|
||||||
|
var durationMinutes = moment.duration(end.diff(start)).minutes();
|
||||||
|
var durationMinutesKey = (durationMinutes === 1) ? 'm' : 'mm';
|
||||||
|
|
||||||
|
var localeData = moment.localeData(); // i18n for 'hours' and "minutes" strings
|
||||||
|
context.eventTime.duration = (durationHours > 0 ? localeData.relativeTime(durationHours, true, durationHoursKey) : '')
|
||||||
|
+ (durationHours > 0 && durationMinutes > 0 ? ', ' : '')
|
||||||
|
+ (durationMinutes > 0 ? localeData.relativeTime(durationMinutes, true, durationMinutesKey) : '');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!this.hideDate) {
|
||||||
|
if (!isSameDayEvent && start.isSame(end, 'month')) {
|
||||||
|
// Simplify date-range if an event occurs into the same month (eg. '4-5 August 2019')
|
||||||
|
context.eventDate.date = start.clone().format('MMMM D') + '-' + end.clone().format('D, YYYY');
|
||||||
|
} else {
|
||||||
|
context.eventDate.date = isSameDayEvent ? start.clone().format('dddd, LL') : start.clone().format('LL') + ' - ' + end.clone().format('LL');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (eventData.record.allday && isSameDayEvent) {
|
||||||
|
context.eventDate.duration = _t("All day");
|
||||||
|
} else if (eventData.record.allday && !isSameDayEvent) {
|
||||||
|
var daysLocaleData = moment.localeData();
|
||||||
|
var days = moment.duration(end.diff(start)).days();
|
||||||
|
context.eventDate.duration = daysLocaleData.relativeTime(days, true, 'dd');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return context;
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* Render event popover
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
* @param {Object} eventData
|
||||||
|
* @param {jQueryElement} $eventElement
|
||||||
|
*/
|
||||||
|
_renderEventPopover: function (eventData, $eventElement) {
|
||||||
|
var self = this;
|
||||||
|
$eventElement.popover({
|
||||||
|
animation: false,
|
||||||
|
delay: {
|
||||||
|
show: 50,
|
||||||
|
hide: 100
|
||||||
|
},
|
||||||
|
trigger: 'manual',
|
||||||
|
html: true,
|
||||||
|
title: eventData.record.display_name,
|
||||||
|
template: qweb.render('CalendarView.event.popover.placeholder', {color: this.getColor(eventData.color_index)}),
|
||||||
|
container: eventData.allDay ? '.fc-view' : '.fc-scroller',
|
||||||
|
}).on('shown.bs.popover', function () {
|
||||||
|
var $popover = $($(this).data('bs.popover').tip);
|
||||||
|
$popover.find('.o_cw_popover_close').on('click', self._unselectEvent.bind(self));
|
||||||
|
// Initialize popover widget
|
||||||
|
var calendarPopover = new self.config.CalendarPopover(self, self._getPopoverContext(eventData));
|
||||||
|
calendarPopover.replace($popover.find('.o_cw_body'));
|
||||||
|
}).popover('show');
|
||||||
|
},
|
||||||
|
|
||||||
//--------------------------------------------------------------------------
|
//--------------------------------------------------------------------------
|
||||||
// Handlers
|
// Handlers
|
||||||
//--------------------------------------------------------------------------
|
//--------------------------------------------------------------------------
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Toggle the sidebar
|
* Remove highlight classes and dispose of popovers
|
||||||
*
|
*
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
_onToggleSidebar: function () {
|
_unselectEvent: function () {
|
||||||
this.trigger_up('toggleFullWidth');
|
this.$('.fc-event').removeClass('o_cw_custom_highlight');
|
||||||
|
this.$('.o_cw_popover').popover('dispose');
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
* @param {OdooEvent} event
|
||||||
|
*/
|
||||||
|
_onEditEvent: function (event) {
|
||||||
|
this._unselectEvent();
|
||||||
|
this.trigger_up('openEvent', {_id: event.data.id});
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
* @param {OdooEvent} event
|
||||||
|
*/
|
||||||
|
_onDeleteEvent: function (event) {
|
||||||
|
this._unselectEvent();
|
||||||
|
this.trigger_up('deleteRecord', {id: event.data.id});
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ var CalendarModel = require('web.CalendarModel');
|
|||||||
var CalendarController = require('web.CalendarController');
|
var CalendarController = require('web.CalendarController');
|
||||||
var CalendarRenderer = require('web.CalendarRenderer');
|
var CalendarRenderer = require('web.CalendarRenderer');
|
||||||
var core = require('web.core');
|
var core = require('web.core');
|
||||||
|
var pyUtils = require('web.py_utils');
|
||||||
var utils = require('web.utils');
|
var utils = require('web.utils');
|
||||||
|
|
||||||
var _lt = core._lt;
|
var _lt = core._lt;
|
||||||
@@ -66,7 +67,8 @@ var CalendarView = AbstractView.extend({
|
|||||||
var fieldName = child.attrs.name;
|
var fieldName = child.attrs.name;
|
||||||
fieldNames.push(fieldName);
|
fieldNames.push(fieldName);
|
||||||
if (!child.attrs.invisible) {
|
if (!child.attrs.invisible) {
|
||||||
displayFields[fieldName] = child.attrs;
|
child.attrs.options = child.attrs.options ? pyUtils.py_eval(child.attrs.options) : {};
|
||||||
|
displayFields[fieldName] = {attrs: child.attrs};
|
||||||
|
|
||||||
if (params.sidebar === false) return; // if we have not sidebar, (eg: Dashboard), we don't use the filter "coworkers"
|
if (params.sidebar === false) return; // if we have not sidebar, (eg: Dashboard), we don't use the filter "coworkers"
|
||||||
|
|
||||||
@@ -102,17 +104,13 @@ var CalendarView = AbstractView.extend({
|
|||||||
'filters': [],
|
'filters': [],
|
||||||
};
|
};
|
||||||
if (fields[fieldName].relation) {
|
if (fields[fieldName].relation) {
|
||||||
if (['res.users', 'res.partner'].indexOf(fields[fieldName].relation) !== -1) {
|
if (['res.users', 'res.partner', 'hr.employee'].indexOf(fields[fieldName].relation) !== -1) {
|
||||||
filters[fieldName].avatar_field = 'image_64';
|
filters[fieldName].avatar_field = 'image_64';
|
||||||
}
|
}
|
||||||
filters[fieldName].avatar_model = fields[fieldName].relation;
|
filters[fieldName].avatar_model = fields[fieldName].relation;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_.isEmpty(displayFields)) {
|
|
||||||
displayFields = fields.display_name ? {'display_name': {}} : [];
|
|
||||||
}
|
|
||||||
|
|
||||||
//if quick_add = False, we don't allow quick_add
|
//if quick_add = False, we don't allow quick_add
|
||||||
//if quick_add = not specified in view, we use the default widgets.QuickCreate
|
//if quick_add = not specified in view, we use the default widgets.QuickCreate
|
||||||
//if quick_add = is NOT False and IS specified in view, we this one for widgets.QuickCreate'
|
//if quick_add = is NOT False and IS specified in view, we this one for widgets.QuickCreate'
|
||||||
@@ -132,15 +130,15 @@ var CalendarView = AbstractView.extend({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.controllerParams.readonlyFormViewId = !attrs.readonly_form_view_id || !utils.toBoolElse(attrs.readonly_form_view_id, true) ? false : attrs.readonly_form_view_id;
|
|
||||||
this.controllerParams.eventOpenPopup = utils.toBoolElse(attrs.event_open_popup || '', false);
|
this.controllerParams.eventOpenPopup = utils.toBoolElse(attrs.event_open_popup || '', false);
|
||||||
this.controllerParams.mapping = mapping;
|
this.controllerParams.mapping = mapping;
|
||||||
this.controllerParams.context = params.context || {};
|
this.controllerParams.context = params.context || {};
|
||||||
this.controllerParams.displayName = params.action && params.action.name;
|
this.controllerParams.displayName = params.action && params.action.name;
|
||||||
|
|
||||||
this.rendererParams.displayFields = displayFields;
|
this.rendererParams.displayFields = displayFields;
|
||||||
this.rendererParams.eventTemplate = _.findWhere(arch.children, {'tag': 'templates'});
|
|
||||||
this.rendererParams.model = viewInfo.model;
|
this.rendererParams.model = viewInfo.model;
|
||||||
|
this.rendererParams.hideDate = utils.toBoolElse(attrs.hide_date || '', false);
|
||||||
|
this.rendererParams.hideTime = utils.toBoolElse(attrs.hide_time || '', false);
|
||||||
|
|
||||||
this.loadParams.fieldNames = _.uniq(fieldNames);
|
this.loadParams.fieldNames = _.uniq(fieldNames);
|
||||||
this.loadParams.mapping = mapping;
|
this.loadParams.mapping = mapping;
|
||||||
|
|||||||
@@ -1,187 +1,658 @@
|
|||||||
|
// Variables
|
||||||
|
$o-cw-color-today: nth($o-colors, 3);
|
||||||
|
$o-cw-color-today-accent: #FC3D39;
|
||||||
|
$o-cw-popup-avatar-size: 16px;
|
||||||
|
$o-cw-filter-avatar-size: 20px;
|
||||||
|
|
||||||
|
// Animations
|
||||||
@keyframes backgroundfade {
|
@keyframes backgroundfade {
|
||||||
from {background-color: rgba($o-brand-odoo, 0.5);}
|
from { background-color: rgba($info, 0.5); }
|
||||||
to {background-color: #f5f5f5;}
|
to { background-color: rgba($info, 0.1); }
|
||||||
}
|
}
|
||||||
|
|
||||||
.o_calendar_container {
|
.o_calendar_container {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
@include o-webclient-padding($top: $o-horizontal-padding/2, $bottom: $o-horizontal-padding/2);
|
|
||||||
display: flex;
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
@for $index from 1 through $o-nb-calendar-colors {
|
.o_calendar_view {
|
||||||
.o_calendar_color_#{$index} {
|
flex: 1 1 auto;
|
||||||
color: #0D0D0D;
|
min-width: 0;
|
||||||
background-color: adjust-hue(rgb(255, 192, 192), (360/($o-nb-calendar-colors+1) * $index) * 1deg);
|
height: 100%;
|
||||||
border-color: adjust-hue(rgb(255, 192, 192), (360/($o-nb-calendar-colors+1) * $index) * 1deg);
|
background-color: gray('100');
|
||||||
opacity: 0.7;
|
background: linear-gradient(-45deg, gray('100'), white);
|
||||||
&.o_event_hightlight {
|
|
||||||
font-weight: bold;
|
.fc-event {
|
||||||
opacity: 0.9;
|
margin: 0 1px;
|
||||||
}
|
border-style: solid;
|
||||||
&:hover {
|
border-width: 0 0 0 3px;
|
||||||
color: #666 !important;
|
border-radius: 0;
|
||||||
}
|
box-sizing: border-box;
|
||||||
|
overflow: hidden;
|
||||||
|
background: none;
|
||||||
|
font-size: 11px;
|
||||||
|
line-height: 1;
|
||||||
|
|
||||||
|
&:not([href]):not([tabindex]) {
|
||||||
|
color: $body-color;
|
||||||
}
|
}
|
||||||
.o_underline_color_#{$index} {
|
|
||||||
border-bottom: 4px solid adjust-hue(rgba(255, 192, 192, 0.7), (360/($o-nb-calendar-colors+1) * $index) * 1deg);
|
.fc-bg {
|
||||||
|
background-color: mix(theme-color('primary'), white); // Used for placeholder events only (on creation)
|
||||||
|
@include size(101%); // Compensate border
|
||||||
|
opacity: 0.9;
|
||||||
|
transition: opacity 0.2s;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
.o_calendar_view {
|
.fc-content {
|
||||||
flex: 1 1 auto;
|
white-space: normal;
|
||||||
min-width: 0;
|
margin: 8px 4px;
|
||||||
|
font-size: 1.1em;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
.o_calendar_widget {
|
&.o_cw_custom_highlight {
|
||||||
height: 100%;
|
z-index: 10!important;
|
||||||
background-color: $o-view-background-color;
|
|
||||||
* {
|
.fc-bg{
|
||||||
z-index: 0; // FIXME
|
opacity: 0.95;
|
||||||
}
|
|
||||||
.fc-week-number, .fc-widget-header {
|
|
||||||
background-color: lighten($o-brand-secondary, 30%);
|
|
||||||
}
|
|
||||||
.o_avatar_square {
|
|
||||||
border-radius: 5px;
|
|
||||||
display: inline-block;
|
|
||||||
opacity: 1;
|
|
||||||
border: 1px solid #999;
|
|
||||||
}
|
|
||||||
.o_fields img, .o_avatar_square {
|
|
||||||
vertical-align: middle;
|
|
||||||
margin-left: 1px;
|
|
||||||
width: 18px;
|
|
||||||
height: 18px;
|
|
||||||
}
|
|
||||||
.o_field_type_char:first-child {
|
|
||||||
font-weight: bold;
|
|
||||||
}
|
|
||||||
.fc-view {
|
|
||||||
overflow-x: auto;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.o_calendar_sidebar_container {
|
.o_calendar_widget {
|
||||||
flex: 0 0 $o-horizontal-padding;
|
height: 100%;
|
||||||
position: relative;
|
|
||||||
|
|
||||||
&.o_sidebar_hidden {
|
// === Adapt calendar table borders ===
|
||||||
margin-right: -$o-horizontal-padding; // hack to display the toggler in the gutter
|
// =====================================
|
||||||
.o_calendar_sidebar_toggler {
|
|
||||||
padding: 4px;
|
td {
|
||||||
color: darken($o-webclient-background-color, 30%);
|
border-color: gray('200');
|
||||||
|
}
|
||||||
|
|
||||||
|
.fc-time-grid .fc-slats .fc-minor td {
|
||||||
|
border-top-color: gray('300');
|
||||||
|
}
|
||||||
|
|
||||||
|
.fc-widget-content {
|
||||||
|
border-left-color: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fc-widget-header {
|
||||||
|
border-color: transparent;
|
||||||
|
border-bottom-color: $gray-200;
|
||||||
|
padding: 3px 0 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
hr.fc-widget-header {
|
||||||
|
padding: 1px;
|
||||||
|
border: 0;
|
||||||
|
background: gray('400');
|
||||||
|
}
|
||||||
|
|
||||||
|
.fc-agenda-view .fc-day-grid .fc-row .fc-content-skeleton {
|
||||||
|
padding: .5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fc-event-container {
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ====== Specific agenda types ======
|
||||||
|
// ====================================
|
||||||
|
|
||||||
|
// ====== Both Day and Week agenda
|
||||||
|
.fc-agendaDay-view, .fc-agendaWeek-view {
|
||||||
|
.fc-axis {
|
||||||
|
padding-left: $o-horizontal-padding;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Hide unnecessary borders
|
||||||
|
table td, div.fc-row.fc-week.fc-widget-content {
|
||||||
|
border-left-color: transparent;
|
||||||
|
border-right-color: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reinfornce default border color
|
||||||
|
tbody td {
|
||||||
|
border-top-color: gray('400');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove dotted borders (half-hours)
|
||||||
|
.fc-time-grid .fc-slats .fc-minor td {
|
||||||
|
border-top-style: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Align labels and timelines
|
||||||
|
.fc-axis.fc-time {
|
||||||
|
border-top-color: transparent;
|
||||||
|
|
||||||
|
span {
|
||||||
|
max-width: 45px;
|
||||||
|
margin-top: -19px;
|
||||||
|
position: relative;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add a small gap on top to show the first time label (0:00)
|
||||||
|
.fc-scroller .fc-time-grid > .fc-slats,
|
||||||
|
.fc-scroller .fc-time-grid > .fc-bg {
|
||||||
|
padding-top: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Row containing "all day" events
|
||||||
|
div.fc-day-grid {
|
||||||
|
background-color: $o-view-background-color;
|
||||||
|
box-shadow: 0 6px 12px -6px rgba(black, 0.16);
|
||||||
|
|
||||||
|
+ hr.fc-widget-header {
|
||||||
|
padding: 1px 0 0;
|
||||||
|
background: gray('300');
|
||||||
|
}
|
||||||
|
|
||||||
|
.fc-content-skeleton tr:not(:first-child) .fc-h-event{
|
||||||
|
margin-top: 3px
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a 'preudo-border' for the first row. The actual border
|
||||||
|
// it's hidden because of border-collapse settings.
|
||||||
|
.fc-slats tr:first-child td.fc-widget-content:last-child {
|
||||||
|
box-shadow: inset 0 1px 0 gray('400');
|
||||||
|
}
|
||||||
|
|
||||||
|
.fc-day.fc-widget-content.fc-today.fc-state-highlight {
|
||||||
|
border-left-color: rgba($o-cw-color-today, 0.3);
|
||||||
|
border-right-color: rgba($o-cw-color-today, 0.3);
|
||||||
|
background: rgba($o-cw-color-today, 0.05 );
|
||||||
|
}
|
||||||
|
|
||||||
|
.fc-event {
|
||||||
|
// Prevent events with similar color to visually overlap each other
|
||||||
|
box-shadow: 0 0 0 1px white;
|
||||||
|
|
||||||
|
&.fc-v-event {
|
||||||
|
border-width: 3px 0 0;
|
||||||
|
|
||||||
|
&.fc-not-start {
|
||||||
|
border-width: 0 0 3px;
|
||||||
|
|
||||||
|
&.fc-not-end {
|
||||||
|
border-width: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reset position to keep the "nowIndicator" line visible
|
||||||
|
.fc-content-col {
|
||||||
|
position: initial;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.o_calendar_sidebar_toggler {
|
// ====== Day only
|
||||||
@include o-position-absolute($top: 0, $right: 0);
|
.fc-agendaDay-view .fc-event {
|
||||||
cursor: pointer;
|
padding: 10px;
|
||||||
padding: 6px;
|
font-size: 14px;
|
||||||
z-index: 1;
|
}
|
||||||
&:hover {
|
|
||||||
color: black;
|
// ====== Week only
|
||||||
|
.fc-agendaWeek-view {
|
||||||
|
.fc-now-indicator {
|
||||||
|
left: $o-horizontal-padding;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Expand tiny events on hover/select
|
||||||
|
.fc-v-event.o_cw_custom_highlight, .fc-v-event.o_cw_custom_hover {
|
||||||
|
transition: margin .1s .3s, left .1s .3s, right .1s .3s;
|
||||||
|
margin: 0!important;
|
||||||
|
right: 1px!important;
|
||||||
|
left: 1px!important;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.o_calendar_sidebar {
|
// ====== Month only
|
||||||
|
.fc-month-view {
|
||||||
|
padding-left: $o-horizontal-padding;
|
||||||
|
|
||||||
|
.fc-widget-header {
|
||||||
|
padding: 3px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fc-week-number {
|
||||||
|
background: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fc-day-number {
|
||||||
|
margin: 5px;
|
||||||
|
padding: 0.1rem 0.3rem 0.1rem 0;
|
||||||
|
font-size: 1.2rem;
|
||||||
|
color: gray('900');
|
||||||
|
font-weight: 400;
|
||||||
|
line-height: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fc-day-top.fc-other-month {
|
||||||
|
opacity: 0.8;
|
||||||
|
|
||||||
|
.fc-day-number {
|
||||||
|
color: gray('500');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
td:last-child {
|
||||||
|
border-right-color: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fc-bg .fc-today {
|
||||||
|
background: $o-view-background-color;
|
||||||
|
border-color: gray('300');
|
||||||
|
}
|
||||||
|
|
||||||
|
.fc-content-skeleton .fc-today .fc-day-number {
|
||||||
|
margin-top: 3px;
|
||||||
|
padding: 0.4em 0.4em 0.35em;
|
||||||
|
border-radius: 100%;
|
||||||
|
min-width: 1.1em;
|
||||||
|
background: $o-cw-color-today-accent;
|
||||||
|
text-align: center;
|
||||||
|
color: white;
|
||||||
|
font-size: 1.1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fc-more-cell {
|
||||||
|
> div, .fc-more {
|
||||||
|
height: 100%;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.fc-event {
|
||||||
|
margin: 0 3px 2px;
|
||||||
|
.o_event_title {
|
||||||
|
@include text-truncate();
|
||||||
|
}
|
||||||
|
|
||||||
|
.fc-content {
|
||||||
|
margin: 4px 4px 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.o_cw_nobg {
|
||||||
|
.fc-bg {
|
||||||
|
visibility: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.o_cw_custom_hover, &.o_cw_custom_highlight, &:hover {
|
||||||
|
.fc-bg {
|
||||||
|
visibility: visible;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.fc-not-start {
|
||||||
|
border-right-width: 3px;
|
||||||
|
|
||||||
|
.fc-content {
|
||||||
|
padding-left: 6px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.fc-not-end {
|
||||||
|
margin-right: 0;
|
||||||
|
|
||||||
|
.fc-content {
|
||||||
|
padding-right: 6px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// ====== RTL layout(s)
|
||||||
|
&.fc-rtl {
|
||||||
|
.fc-agendaWeek-view .fc-event {
|
||||||
|
border-width: 0 3px 0 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fc-month-view .fc-event {
|
||||||
|
border-width: 0 3px 0 0;
|
||||||
|
|
||||||
|
&.fc-not-start {
|
||||||
|
margin: 0 0 1px 5px;
|
||||||
|
border-width: 0 0 0 3px;
|
||||||
|
|
||||||
|
.fc-content {
|
||||||
|
padding-right: 6px;
|
||||||
|
padding-left: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.fc-not-end {
|
||||||
|
margin: 0 5px 1px 0;
|
||||||
|
|
||||||
|
.fc-content {
|
||||||
|
padding-left: 6px;
|
||||||
|
padding-right: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.o_calendar_sidebar_container {
|
||||||
|
flex: 0 0 auto;
|
||||||
|
position: relative;
|
||||||
|
@include o-webclient-padding($top: $o-horizontal-padding/2);
|
||||||
|
background-color: $o-view-background-color;
|
||||||
|
border-left: 1px solid darken($o-control-panel-background-color, 20%);
|
||||||
|
overflow-y:auto;
|
||||||
|
|
||||||
|
.o_calendar_sidebar {
|
||||||
|
width: 200px;
|
||||||
|
font-size: 14px;
|
||||||
|
|
||||||
|
@include media-breakpoint-up('xl') {
|
||||||
width: 250px;
|
width: 250px;
|
||||||
margin-left: 8px;
|
}
|
||||||
background: $o-view-background-color;
|
}
|
||||||
|
|
||||||
|
.ui-datepicker {
|
||||||
|
margin: 0;
|
||||||
|
width: 100%;
|
||||||
|
padding: 0;
|
||||||
|
|
||||||
|
&, td, .ui-datepicker-header, td a, td span {
|
||||||
|
border: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.ui-datepicker {
|
th {
|
||||||
width: 100%;
|
padding: .7em .2em;
|
||||||
font-size: 8pt;
|
}
|
||||||
border-radius: 0;
|
|
||||||
border: none;
|
td {
|
||||||
padding: 0;
|
padding: 0;
|
||||||
|
|
||||||
.ui-widget-header {
|
a, span {
|
||||||
display: flex;
|
padding: .2em .2em .1em;
|
||||||
|
float: right;
|
||||||
|
width: 22px;
|
||||||
background: none;
|
background: none;
|
||||||
background-color: lighten($o-brand-secondary, 30%);
|
text-align: center;
|
||||||
border-radius: 0;
|
color: gray('700');
|
||||||
|
}
|
||||||
|
|
||||||
.ui-datepicker-prev, .ui-datepicker-next {
|
&.ui-datepicker-current-day a {
|
||||||
flex: 0 0 auto;
|
background: $info;
|
||||||
position: static;
|
color: color-yiq($info);
|
||||||
cursor: pointer;
|
font-weight: bold;
|
||||||
padding: 2px;
|
}
|
||||||
text-align: center;
|
|
||||||
color: $o-main-text-color;
|
&.ui-datepicker-today a {
|
||||||
&.ui-state-hover {
|
border-radius: 100%;
|
||||||
background: none;
|
padding-top: 0.3em;
|
||||||
border: none;
|
width: 25px;
|
||||||
color: black;
|
background: mix($o-cw-color-today-accent, white, 80%);
|
||||||
}
|
font-weight: bold;
|
||||||
.ui-icon {
|
color: white;
|
||||||
display: none;
|
}
|
||||||
}
|
|
||||||
|
&.ui-datepicker-current-day.ui-datepicker-today a {
|
||||||
|
background: $o-cw-color-today-accent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.ui-datepicker-header {
|
||||||
|
background: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ui-datepicker-header {
|
||||||
|
border-radius: 0;
|
||||||
|
|
||||||
|
.ui-icon {
|
||||||
|
background-image: none;
|
||||||
|
text-indent: 0;
|
||||||
|
color: transparent;
|
||||||
|
|
||||||
|
&:before {
|
||||||
|
font: normal normal normal 13px/1 FontAwesome;
|
||||||
|
content: "\f053";
|
||||||
|
color: gray('400');
|
||||||
}
|
}
|
||||||
.ui-datepicker-prev {
|
&.ui-icon-circle-triangle-e:before {
|
||||||
order: 1;
|
content: "\f054"
|
||||||
&:after {
|
|
||||||
font-family: FontAwesome;
|
|
||||||
content: "";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.ui-datepicker-next {
|
|
||||||
order: 3;
|
|
||||||
&:before {
|
|
||||||
font-family: FontAwesome;
|
|
||||||
content: "";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.ui-datepicker-title {
|
|
||||||
flex: 0 0 auto;
|
|
||||||
order: 2;
|
|
||||||
display: inline-block;
|
|
||||||
margin: 0 10px;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
table {
|
|
||||||
td {
|
.ui-state-hover.ui-datepicker-next-hover, .ui-state-hover.ui-datepicker-prev-hover {
|
||||||
padding: 0 2px 2px 0;
|
background: none;
|
||||||
background-color: $o-view-background-color;
|
border: none;
|
||||||
a {
|
cursor: pointer;
|
||||||
border: none;
|
|
||||||
background: none;
|
span:before {
|
||||||
background-color: lighten($o-brand-secondary, 40%);
|
color: gray('800');
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.ui-state-default {
|
|
||||||
color: $o-brand-odoo;
|
|
||||||
&:hover {
|
|
||||||
background: none;
|
|
||||||
background-color: rgba($o-brand-odoo, 0.5);
|
|
||||||
border-color: $o-brand-odoo;
|
|
||||||
color: $o-view-background-color;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
.ui-state-active {
|
|
||||||
background: none;
|
|
||||||
background-color: $o-brand-odoo;
|
|
||||||
color: $o-view-background-color;
|
|
||||||
}
|
|
||||||
.o_selected_range.o_color {
|
|
||||||
background: none;
|
|
||||||
background-color: $o-brand-odoo;
|
|
||||||
animation: backgroundfade 3s forwards;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.o_calendar_filter {
|
|
||||||
padding: 8px;
|
.o_selected_range.o_color:not(.ui-datepicker-unselectable) {
|
||||||
border-top: 1px solid lightgray;
|
background-color: $info;
|
||||||
.o_field_many2one {
|
animation: backgroundfade 2s forwards;
|
||||||
width: 100%;
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.o_calendar_filter {
|
||||||
|
font-size: 0.9em;
|
||||||
|
padding: 2em 0 1em;
|
||||||
|
|
||||||
|
.o_cw_filter_collapse_icon {
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
@include o-hover-opacity();
|
||||||
|
font-size: 0.7em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.collapsed .o_cw_filter_collapse_icon {
|
||||||
|
transform: rotate(90deg);
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.o_calendar_filter_item {
|
||||||
|
cursor: pointer;
|
||||||
|
overflow: hidden;
|
||||||
|
|
||||||
|
input {
|
||||||
|
z-index: -1;
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.o_cw_filter_input_bg {
|
||||||
|
@include size(1.3em);
|
||||||
|
border-width: 2px;
|
||||||
|
border-style: solid;
|
||||||
|
border-radius: 1px;
|
||||||
|
overflow: hidden;
|
||||||
|
|
||||||
|
&.o_beside_avatar {
|
||||||
|
@include size($o-cw-filter-avatar-size);
|
||||||
|
border-radius: 2px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
input:not(:checked) + label .o_cw_filter_input_bg {
|
||||||
|
background: transparent!important;
|
||||||
|
|
||||||
|
i.fa {
|
||||||
|
visibility: hidden;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.o_cw_filter_avatar {
|
||||||
|
@include size($o-cw-filter-avatar-size);
|
||||||
|
border-radius: 2px;
|
||||||
|
|
||||||
|
&.fa {
|
||||||
|
padding: 4px 3px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.o_cw_filter_title {
|
||||||
|
line-height: 1;
|
||||||
|
flex-grow: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
button.o_remove {
|
||||||
|
@include o-position-absolute(0,0,0);
|
||||||
|
transform: translateX(100%);
|
||||||
|
transition: transform 0.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
button.o_remove {
|
||||||
|
transform: translateX(0%);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.o_field_many2one {
|
||||||
|
margin-top: 1rem;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.o_cw_popover {
|
||||||
|
min-width: 256px;
|
||||||
|
max-width: 328px;
|
||||||
|
font-size: $font-size-base;
|
||||||
|
|
||||||
|
.card-header, .card-header .popover-header {
|
||||||
|
font-size: 1.05em;
|
||||||
|
font-weight: 500;
|
||||||
|
line-height: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.o_cw_popover_close {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.o_calendar_avatars {
|
||||||
|
line-height: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.o_calendar_avatars img {
|
||||||
|
margin-right: 0.4rem;
|
||||||
|
@include size($o-cw-popup-avatar-size);
|
||||||
|
border-radius: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.list-group-item {
|
||||||
|
padding: 0.5rem 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.o_cw_popover_fields_secondary {
|
||||||
|
max-height: 170px; // Fallback for old browsers
|
||||||
|
max-height: 25vh;
|
||||||
|
overflow-y: auto;
|
||||||
|
|
||||||
|
&::-webkit-scrollbar {
|
||||||
|
background: gray('200');
|
||||||
|
width: 6px;
|
||||||
|
}
|
||||||
|
&::-webkit-scrollbar-thumb {
|
||||||
|
background: gray('500');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.fc-rtl & {
|
||||||
|
text-align: right;
|
||||||
|
.o_calendar_avatars {
|
||||||
|
> div {
|
||||||
|
justify-content: flex-end;
|
||||||
|
}
|
||||||
|
img {
|
||||||
|
order: 2;
|
||||||
|
margin: 0 0 0 0.4rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// =============== Generate color classes ===============
|
||||||
|
// These colors are specifically designed for calendar
|
||||||
|
// =============== =============== ======================
|
||||||
|
$o-cw-colors: (
|
||||||
|
#5e0231, // 1:
|
||||||
|
#97743a, // 2:
|
||||||
|
#F4A460, // 3:
|
||||||
|
#F7CD1F, // 4:
|
||||||
|
#6CC1ED, // 5:
|
||||||
|
#4285F4, // 6: Default User
|
||||||
|
#8E24AA, // 7:
|
||||||
|
#2C8397, // 8:
|
||||||
|
#475577, // 9:
|
||||||
|
#D6145F, // 10:
|
||||||
|
#30C381, // 11:
|
||||||
|
#9365B8, // 12:
|
||||||
|
#aa4b6b, // 13:
|
||||||
|
#348F50, // 14:
|
||||||
|
#AA3A38, // 15:
|
||||||
|
#173e43, // 16:
|
||||||
|
#134E5E, // 17:
|
||||||
|
#795548, // 18:
|
||||||
|
#6be585, // 19:
|
||||||
|
#999966, // 20:
|
||||||
|
#e9d362, // 21:
|
||||||
|
#b56969, // 22:
|
||||||
|
#bdc3c7, // 23:
|
||||||
|
#649173, // 24:
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
@for $i from 1 to length($o-cw-colors) + 1 {
|
||||||
|
$color: nth($o-cw-colors, $i);
|
||||||
|
|
||||||
|
.o_calendar_view .fc-view {
|
||||||
|
.fc-event.o_calendar_color_#{$i} {
|
||||||
|
border-color: $color;
|
||||||
|
color: darken($color, 35%);
|
||||||
|
|
||||||
|
.fc-bg {
|
||||||
|
background: mix($color, white);
|
||||||
|
}
|
||||||
|
|
||||||
|
&.o_cw_custom_hover, &.o_cw_custom_highlight {
|
||||||
|
box-shadow: 0 12px 12px -5px rgba($color, 0.3);
|
||||||
|
color: color-yiq($color);
|
||||||
|
|
||||||
|
.fc-bg {
|
||||||
|
background: $color;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.fc-time-grid-event.fc-short .fc-time:before {
|
.o_cw_filter_color_#{$i} {
|
||||||
content: '';
|
.o_cw_filter_input_bg {
|
||||||
|
border-color: $color;
|
||||||
|
background: $color;
|
||||||
|
color: color-yiq($color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.o_cw_popover.o_calendar_color_#{$i} {
|
||||||
|
$color-subdle: mix(white, $color, 90%);
|
||||||
|
|
||||||
|
.card-header, .card-header .popover-header {
|
||||||
|
background-color: $color-subdle;
|
||||||
|
color: color-yiq($color-subdle);
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-header {
|
||||||
|
border-color: mix($card-border-color, mix(white, $color));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,4 @@
|
|||||||
@include media-breakpoint-down(sm) {
|
@include media-breakpoint-down(sm) {
|
||||||
.o_calendar_container {
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.o_control_panel {
|
.o_control_panel {
|
||||||
.o_calendar_button_today {
|
.o_calendar_button_today {
|
||||||
font-size: 0.7em;
|
font-size: 0.7em;
|
||||||
|
|||||||
@@ -5,7 +5,6 @@
|
|||||||
<div class="o_calendar_widget" />
|
<div class="o_calendar_widget" />
|
||||||
</div>
|
</div>
|
||||||
<div class="o_calendar_sidebar_container d-none d-md-block">
|
<div class="o_calendar_sidebar_container d-none d-md-block">
|
||||||
<i class="o_calendar_sidebar_toggler fa"/>
|
|
||||||
<div class="o_calendar_sidebar">
|
<div class="o_calendar_sidebar">
|
||||||
<div class="o_calendar_mini"/>
|
<div class="o_calendar_mini"/>
|
||||||
</div>
|
</div>
|
||||||
@@ -13,58 +12,81 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<t t-name="calendar-box">
|
<t t-name="calendar-box">
|
||||||
<t t-set="color" t-value="widget.getColor(event.color_index)"/>
|
<div t-att-style="typeof color === 'string' ? ('background-color:' + color) + ';' : ''" t-attf-class="#{!event.color_index ? 'text-white' : ''} #{record.is_highlighted and record.is_highlighted.value ? 'o_event_hightlight' : ''} #{typeof color === 'number' ? _.str.sprintf('o_calendar_color_%s', color) : ''}">
|
||||||
<div t-att-style="typeof color === 'string' ? ('background-color:'+color)+';' : ''" t-attf-class="#{!event.color_index ? 'text-white' : ''} #{record.is_highlighted && record.is_highlighted.value ? 'o_event_hightlight' : ''} #{typeof color === 'number' ? 'o_calendar_color_'+color : ''}">
|
<div class="o_event_title" t-esc="record.display_name"/>
|
||||||
<div class="fc-time"/>
|
</div>
|
||||||
<div class="o_fields">
|
</t>
|
||||||
<t t-foreach="widget.displayFields" t-as="name">
|
|
||||||
<div t-attf-class="o_field_#{name} o_field_type_#{fields[name].type}">
|
<t t-name="CalendarView.event.popover.placeholder">
|
||||||
<t t-if="widget.displayFields[name].avatar_field">
|
<div t-attf-class="o_cw_popover popover card shadow #{typeof color === 'number' ? _.str.sprintf('o_calendar_color_%s', color) : ''}" role="tooltip">
|
||||||
<t t-if="!isMobile"><t t-esc="fields[name].string"/>:</t>
|
<div class="arrow"/>
|
||||||
<div class="o_calendar_avatars float-right">
|
<div class="card-header d-flex justify-content-between py-2 pr-2">
|
||||||
<t t-foreach="widget.getAvatars(record, name, widget.displayFields[name].avatar_field).slice(0,3)" t-as="image"><t t-raw="image"/></t>
|
<h4 class="popover-header border-0 p-0 pt-1"/>
|
||||||
<span t-if="record[name].length - 3 > 0">+<t t-esc="record[name].length - 3"/></span>
|
<span class="o_cw_popover_close ml-4"><i class="fa fa-close small"/></span>
|
||||||
</div>
|
</div>
|
||||||
</t>
|
<div class="o_cw_body">
|
||||||
<t t-else="">
|
<div class="py-4 text-center">
|
||||||
<t t-esc="format(record, name)"/>
|
<i class="fa fa-spinner fa-spin fa-2x"></i>
|
||||||
</t>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</t>
|
</div>
|
||||||
|
</t>
|
||||||
|
|
||||||
|
<t t-name="CalendarView.event.popover">
|
||||||
|
<div class="o_cw_body">
|
||||||
|
<ul class="list-group list-group-flush">
|
||||||
|
<li t-if="!widget.hideDate and widget.eventDate.date" class="list-group-item">
|
||||||
|
<i class="fa fa-fw fa-calendar-o"/>
|
||||||
|
<b class="text-capitalize" t-esc="widget.eventDate.date"/> <small t-if="widget.eventDate.duration"><b t-esc="_.str.sprintf('(%s)', widget.eventDate.duration)"/></small>
|
||||||
|
</li>
|
||||||
|
<li t-if="!widget.hideTime and widget.eventTime.time" class="list-group-item">
|
||||||
|
<i class="fa fa-fw fa-clock-o"/>
|
||||||
|
<b t-esc="widget.eventTime.time"/> <small t-if="widget.eventTime.duration"><b t-esc="_.str.sprintf('(%s)', widget.eventTime.duration)"/></small>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<ul class="list-group list-group-flush o_cw_popover_fields_secondary"/>
|
||||||
|
<div class="card-footer border-top">
|
||||||
|
<a href="#" class="btn btn-primary o_cw_popover_edit">Edit</a>
|
||||||
|
<a href="#" class="btn btn-secondary o_cw_popover_delete ml-2">Delete</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</t>
|
</t>
|
||||||
|
|
||||||
<t t-name="CalendarView.sidebar.filter">
|
<t t-name="CalendarView.sidebar.filter">
|
||||||
|
<t t-set="needCollapse" t-value="widget.filters.length > 2 and widget.title"></t>
|
||||||
<div class="o_calendar_filter">
|
<div class="o_calendar_filter">
|
||||||
<h3 t-if="widget.title"><t t-esc="widget.title"/></h3>
|
<h5 t-if="needCollapse" type="button" data-toggle="collapse" t-attf-data-target="#o_cw_filter_collapse_#{widget.title}" class="d-flex justify-content-between align-items-center">
|
||||||
<div class="o_calendar_filter_items">
|
<t t-esc="widget.title"/><i class="o_cw_filter_collapse_icon fa fa-chevron-down"/>
|
||||||
<div t-foreach="widget.filters" t-as="filter" t-if="filter.display == null || filter.display" class="o_calendar_filter_item" t-att-data-value="filter.value" t-att-data-id="filter.id">
|
</h5>
|
||||||
<t t-set="id_for_label" t-value="_.uniqueId('o_calendar_filter_item_')"/>
|
|
||||||
<div class="custom-control custom-control-inline custom-checkbox">
|
<h5 t-elif="widget.title" t-esc="widget.title"/>
|
||||||
<input type="checkbox"
|
|
||||||
t-att-id="id_for_label"
|
<div t-attf-class="o_calendar_filter_items #{needCollapse ? 'collapse show' : 0}" aria-expanded="true" t-attf-id="o_cw_filter_collapse_#{widget.title}">
|
||||||
name="selection"
|
<t t-foreach="widget.filters" t-as="filter" t-if="filter.display == null || filter.display">
|
||||||
class="custom-control-input"
|
<t t-set="idForLabel" t-value="_.uniqueId('o_calendar_filter_item_')"/>
|
||||||
t-att-checked="(filter.active ? true : undefined)"/>
|
<t t-set="color" t-value="widget.getColor(filter.color_index)"/>
|
||||||
<label t-att-for="id_for_label"
|
<t t-set="isColorNumber" t-value="typeof color === 'number'"/>
|
||||||
class="custom-control-label">
|
|
||||||
<t t-if="filter.value == 'all'">
|
<div t-attf-class="o_calendar_filter_item w-100 position-relative mb-2 #{isColorNumber ? _.str.sprintf('o_cw_filter_color_%s', color) : ''}"
|
||||||
<span><i class="fa fa-users fa-fw o_cal_avatar" role="img" aria-label="Avatar" title="Avatar"/></span>
|
t-att-data-value="filter.value" t-att-data-id="filter.id">
|
||||||
</t>
|
|
||||||
<t t-if="widget.avatar_field && (filter.value && filter.value != 'all')">
|
<input type="checkbox" t-att-id="idForLabel" name="selection" class="position-absolute" t-att-checked="filter.active ? true : undefined"/>
|
||||||
<img t-attf-src="/web/image/#{widget.avatar_model}/#{filter.value}/#{widget.avatar_field}" class="o_cal_avatar" alt="Avatar"/>
|
|
||||||
</t>
|
<label t-att-for="idForLabel" class="d-flex align-items-center m-0">
|
||||||
<t t-set="color" t-value="widget.getColor(filter.color_index)"/>
|
<span t-attf-class="o_cw_filter_input_bg align-items-center d-flex flex-shrink-0 justify-content-center position-relative mr-1 #{widget.avatar_field ? 'o_beside_avatar' : ''}"
|
||||||
<span t-if="typeof color === 'number'" t-attf-class="color_filter o_underline_color_#{widget.getColor(filter.color_index)}"><t t-esc="filter.label"/></span>
|
t-att-style="color and !isColorNumber ? _.str.sprintf('border-color:%s;background-color:%s', color, color) : ''">
|
||||||
<span t-elif="color" t-attf-style="border-bottom: 4px solid #{color};"><t t-esc="filter.label"/></span>
|
<i class="fa fa-check position-relative"/>
|
||||||
<span t-else=""><t t-esc="filter.label"/></span>
|
</span>
|
||||||
|
<i t-if="filter.value == 'all'" class="o_cw_filter_avatar fa fa-users fa-fw flex-shrink-0 mr-1" role="img" aria-label="Avatar" title="Avatar"/>
|
||||||
|
<img t-elif="widget.avatar_field and filter.value" t-attf-src="/web/image/#{widget.avatar_model}/#{filter.value}/#{widget.avatar_field}" class="o_cw_filter_avatar flex-shrink-0 mr-1" alt="Avatar"/>
|
||||||
|
<span class="o_cw_filter_title text-truncate flex-grow" t-esc="filter.label" t-att-title="filter.label"/>
|
||||||
</label>
|
</label>
|
||||||
|
|
||||||
|
<button t-if="filter.id" class="o_remove btn bg-white text-700 py-0 px-2" title="Remove this favorite from the list" role="img" aria-label="Remove this favorite from the list">
|
||||||
|
<i class="fa fa-times"/>
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<t t-if="filter.id">
|
</t>
|
||||||
<span class="o_remove fa fa-times" title="Remove this favorite from the list" role="img" aria-label="Remove this favorite from the list"/>
|
|
||||||
</t>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</t>
|
</t>
|
||||||
|
|||||||
@@ -161,7 +161,6 @@ QUnit.module('Views', {
|
|||||||
'mode="week" '+
|
'mode="week" '+
|
||||||
'attendee="partner_ids" '+
|
'attendee="partner_ids" '+
|
||||||
'color="partner_id">'+
|
'color="partner_id">'+
|
||||||
'<field name="name"/>'+
|
|
||||||
'<filter name="user_id" avatar_field="image"/>'+
|
'<filter name="user_id" avatar_field="image"/>'+
|
||||||
'<field name="partner_ids" write_model="filter_partner" write_field="partner_id"/>'+
|
'<field name="partner_ids" write_model="filter_partner" write_field="partner_id"/>'+
|
||||||
'</calendar>',
|
'</calendar>',
|
||||||
@@ -179,7 +178,7 @@ QUnit.module('Views', {
|
|||||||
// test view scales
|
// test view scales
|
||||||
assert.containsN(calendar, '.fc-event', 9,
|
assert.containsN(calendar, '.fc-event', 9,
|
||||||
"should display 9 events on the week (4 event + 5 days event)");
|
"should display 9 events on the week (4 event + 5 days event)");
|
||||||
assert.containsN($sidebar, '.o_selected_range', 7,
|
assert.containsN($sidebar, 'tr:has(.ui-state-active) td', 7,
|
||||||
"week scale should highlight 7 days in mini calendar");
|
"week scale should highlight 7 days in mini calendar");
|
||||||
|
|
||||||
await testUtils.dom.click(calendar.$buttons.find('.o_calendar_button_day')); // display only one day
|
await testUtils.dom.click(calendar.$buttons.find('.o_calendar_button_day')); // display only one day
|
||||||
@@ -190,44 +189,44 @@ QUnit.module('Views', {
|
|||||||
await testUtils.dom.click(calendar.$buttons.find('.o_calendar_button_month')); // display all the month
|
await testUtils.dom.click(calendar.$buttons.find('.o_calendar_button_month')); // display all the month
|
||||||
assert.containsN(calendar, '.fc-event', 7,
|
assert.containsN(calendar, '.fc-event', 7,
|
||||||
"should display 7 events on the month (5 events + 2 week event - 1 'event 6' is filtered + 1 'Undefined event')");
|
"should display 7 events on the month (5 events + 2 week event - 1 'event 6' is filtered + 1 'Undefined event')");
|
||||||
assert.containsN($sidebar, '.o_selected_range', 31,
|
assert.containsN($sidebar, 'td a', 31,
|
||||||
"month scale should highlight all days in mini calendar");
|
"month scale should highlight all days in mini calendar");
|
||||||
|
|
||||||
// test filters
|
// test filters
|
||||||
assert.containsN($sidebar, '.o_calendar_filter', 2, "should display 2 filters");
|
assert.containsN($sidebar, '.o_calendar_filter', 2, "should display 2 filters");
|
||||||
|
|
||||||
var $typeFilter = $sidebar.find('.o_calendar_filter:has(h3:contains(user))');
|
var $typeFilter = $sidebar.find('.o_calendar_filter:has(h5:contains(user))');
|
||||||
assert.ok($typeFilter.length, "should display 'user' filter");
|
assert.ok($typeFilter.length, "should display 'user' filter");
|
||||||
assert.containsN($typeFilter, '.o_calendar_filter_item', 3, "should display 3 filter items for 'user'");
|
assert.containsN($typeFilter, '.o_calendar_filter_item', 3, "should display 3 filter items for 'user'");
|
||||||
|
|
||||||
// filters which has no value should show with string "Undefined", should not have any user image and should show at the last
|
// filters which has no value should show with string "Undefined", should not have any user image and should show at the last
|
||||||
assert.strictEqual($typeFilter.find('.o_calendar_filter_item:last').data('value'), false, "filters having false value should be displayed at last in filter items");
|
assert.strictEqual($typeFilter.find('.o_calendar_filter_item:last').data('value'), false, "filters having false value should be displayed at last in filter items");
|
||||||
assert.strictEqual($typeFilter.find('.o_calendar_filter_item:last span').text(), "Undefined", "filters having false value should display 'Undefined' string");
|
assert.strictEqual($typeFilter.find('.o_calendar_filter_item:last .o_cw_filter_title').text(), "Undefined", "filters having false value should display 'Undefined' string");
|
||||||
assert.strictEqual($typeFilter.find('.o_calendar_filter_item:last label img').length, 0, "filters having false value should not have any user image");
|
assert.strictEqual($typeFilter.find('.o_calendar_filter_item:last label img').length, 0, "filters having false value should not have any user image");
|
||||||
|
|
||||||
var $attendeesFilter = $sidebar.find('.o_calendar_filter:has(h3:contains(attendees))');
|
var $attendeesFilter = $sidebar.find('.o_calendar_filter:has(h5:contains(attendees))');
|
||||||
assert.ok($attendeesFilter.length, "should display 'attendees' filter");
|
assert.ok($attendeesFilter.length, "should display 'attendees' filter");
|
||||||
assert.containsN($attendeesFilter, '.o_calendar_filter_item', 3, "should display 3 filter items for 'attendees' who use write_model (2 saved + Everything)");
|
assert.containsN($attendeesFilter, '.o_calendar_filter_item', 3, "should display 3 filter items for 'attendees' who use write_model (2 saved + Everything)");
|
||||||
assert.ok($attendeesFilter.find('.o_field_many2one').length, "should display one2many search bar for 'attendees' filter");
|
assert.ok($attendeesFilter.find('.o_field_many2one').length, "should display one2many search bar for 'attendees' filter");
|
||||||
|
|
||||||
assert.containsN(calendar, '.fc-event', 7,
|
assert.containsN(calendar, '.fc-event', 7,
|
||||||
"should display 7 events ('event 5' counts for 2 because it spans two weeks and thus generate two fc-event elements)");
|
"should display 7 events ('event 5' counts for 2 because it spans two weeks and thus generate two fc-event elements)");
|
||||||
await testUtils.dom.click(calendar.$('.o_calendar_filter .custom-checkbox input').first());
|
await testUtils.dom.click(calendar.$('.o_calendar_filter input[type="checkbox"]').first());
|
||||||
assert.containsN(calendar, '.fc-event', 4, "should now only display 4 event");
|
assert.containsN(calendar, '.fc-event', 4, "should now only display 4 event");
|
||||||
await testUtils.dom.click(calendar.$('.o_calendar_filter .custom-checkbox input').eq(1));
|
await testUtils.dom.click(calendar.$('.o_calendar_filter input[type="checkbox"]').eq(1));
|
||||||
assert.containsNone(calendar, '.fc-event', "should not display any event anymore");
|
assert.containsNone(calendar, '.fc-event', "should not display any event anymore");
|
||||||
|
|
||||||
// test search bar in filter
|
// test search bar in filter
|
||||||
await testUtils.dom.click($sidebar.find('input[type="text"]'));
|
await testUtils.dom.click($sidebar.find('input[type="text"]'));
|
||||||
assert.strictEqual($('ul.ui-autocomplete li:not(.o_m2o_dropdown_option)').length, 2,"should display 2 choices in one2many autocomplete"); // TODO: remove :not(.o_m2o_dropdown_option) because can't have "create & edit" choice
|
assert.strictEqual($('ul.ui-autocomplete li:not(.o_m2o_dropdown_option)').length, 2,"should display 2 choices in one2many autocomplete"); // TODO: remove :not(.o_m2o_dropdown_option) because can't have "create & edit" choice
|
||||||
await testUtils.dom.click($('ul.ui-autocomplete li:first'));
|
await testUtils.dom.click($('ul.ui-autocomplete li:first'));
|
||||||
assert.containsN($sidebar, '.o_calendar_filter:has(h3:contains(attendees)) .o_calendar_filter_item', 4, "should display 4 filter items for 'attendees'");
|
assert.containsN($sidebar, '.o_calendar_filter:has(h5:contains(attendees)) .o_calendar_filter_item', 4, "should display 4 filter items for 'attendees'");
|
||||||
await testUtils.dom.click($sidebar.find('input[type="text"]'));
|
await testUtils.dom.click($sidebar.find('input[type="text"]'));
|
||||||
assert.strictEqual($('ul.ui-autocomplete li:not(.o_m2o_dropdown_option)').text(), "partner 4", "should display the last choice in one2many autocomplete"); // TODO: remove :not(.o_m2o_dropdown_option) because can't have "create & edit" choice
|
assert.strictEqual($('ul.ui-autocomplete li:not(.o_m2o_dropdown_option)').text(), "partner 4", "should display the last choice in one2many autocomplete"); // TODO: remove :not(.o_m2o_dropdown_option) because can't have "create & edit" choice
|
||||||
await testUtils.dom.click($sidebar.find('.o_calendar_filter_item .o_remove').first(), {allowInvisible: true});
|
await testUtils.dom.click($sidebar.find('.o_calendar_filter_item .o_remove').first(), {allowInvisible: true});
|
||||||
assert.ok($('.modal-footer button.btn:contains(Ok)').length, "should display the confirm message");
|
assert.ok($('.modal-footer button.btn:contains(Ok)').length, "should display the confirm message");
|
||||||
await testUtils.dom.click($('.modal-footer button.btn:contains(Ok)'));
|
await testUtils.dom.click($('.modal-footer button.btn:contains(Ok)'));
|
||||||
assert.containsN($sidebar, '.o_calendar_filter:has(h3:contains(attendees)) .o_calendar_filter_item', 3, "click on remove then should display 3 filter items for 'attendees'");
|
assert.containsN($sidebar, '.o_calendar_filter:has(h5:contains(attendees)) .o_calendar_filter_item', 3, "click on remove then should display 3 filter items for 'attendees'");
|
||||||
calendar.destroy();
|
calendar.destroy();
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -235,9 +234,7 @@ QUnit.module('Views', {
|
|||||||
assert.expect(3);
|
assert.expect(3);
|
||||||
|
|
||||||
var archs = {
|
var archs = {
|
||||||
'event,1,calendar': '<calendar date_start="start" date_stop="stop" all_day="allday">' +
|
'event,1,calendar': '<calendar date_start="start" date_stop="stop" all_day="allday"/>',
|
||||||
'<field name="name"/>' +
|
|
||||||
'</calendar>',
|
|
||||||
'event,false,search': '<search></search>',
|
'event,false,search': '<search></search>',
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -290,11 +287,14 @@ QUnit.module('Views', {
|
|||||||
'date_start="start" '+
|
'date_start="start" '+
|
||||||
'date_stop="stop" '+
|
'date_stop="stop" '+
|
||||||
'all_day="allday" '+
|
'all_day="allday" '+
|
||||||
'mode="month" '+
|
'mode="month"/>',
|
||||||
'readonly_form_view_id="1">'+
|
|
||||||
'<field name="name"/>'+
|
|
||||||
'</calendar>',
|
|
||||||
archs: archs,
|
archs: archs,
|
||||||
|
mockRPC: function (route, args) {
|
||||||
|
if (args.method === 'write') {
|
||||||
|
assert.deepEqual(args.args[1], {name: 'event 4 modified'}, "should update the record");
|
||||||
|
}
|
||||||
|
return this._super.apply(this, arguments);
|
||||||
|
},
|
||||||
viewOptions: {
|
viewOptions: {
|
||||||
initialDate: initialDate,
|
initialDate: initialDate,
|
||||||
},
|
},
|
||||||
@@ -306,20 +306,19 @@ QUnit.module('Views', {
|
|||||||
|
|
||||||
await testUtils.dom.click(calendar.$('.fc-event:contains(event 4) .fc-content'));
|
await testUtils.dom.click(calendar.$('.fc-event:contains(event 4) .fc-content'));
|
||||||
|
|
||||||
|
assert.ok(calendar.$('.o_cw_popover').length, "should open a popover clicking on event");
|
||||||
|
assert.ok(calendar.$('.o_cw_popover .o_cw_popover_edit').length, "popover should have an edit button");
|
||||||
|
assert.ok(calendar.$('.o_cw_popover .o_cw_popover_delete').length, "popover should have a delete button");
|
||||||
|
assert.ok(calendar.$('.o_cw_popover .o_cw_popover_close').length, "popover should have a close button");
|
||||||
|
|
||||||
|
await testUtils.dom.click(calendar.$('.o_cw_popover .o_cw_popover_edit'));
|
||||||
|
|
||||||
assert.ok($('.modal-body').length, "should open the form view in dialog when click on event");
|
assert.ok($('.modal-body').length, "should open the form view in dialog when click on event");
|
||||||
assert.ok($('.modal-footer button.btn:contains(Edit)').length, "formViewDialog should be in readonly mode");
|
|
||||||
assert.ok($('.modal-footer button.btn:contains(Delete)').length, "formViewDialog should have a delete button");
|
|
||||||
|
|
||||||
await testUtils.dom.click($('.modal-footer button.btn:contains(Edit)'));
|
|
||||||
|
|
||||||
assert.ok($('.modal-body').length, "should switch the modal in edit mode");
|
|
||||||
assert.notOk($('.modal-footer button.btn:contains(Delete)').length, "formViewDialog should not have a delete button in edit mode");
|
|
||||||
|
|
||||||
await testUtils.fields.editInput($('.modal-body input:first'), 'event 4 modified');
|
await testUtils.fields.editInput($('.modal-body input:first'), 'event 4 modified');
|
||||||
await testUtils.dom.click($('.modal-footer button.btn:contains(Save)'));
|
await testUtils.dom.click($('.modal-footer button.btn:contains(Save)'));
|
||||||
|
|
||||||
assert.notOk($('.modal-body').length, "save button should close the modal");
|
assert.notOk($('.modal-body').length, "save button should close the modal");
|
||||||
assert.ok(calendar.$('.fc-event:contains(event 4 modified)').length, "should display the updated records");
|
|
||||||
|
|
||||||
// create a new event, quick create only
|
// create a new event, quick create only
|
||||||
|
|
||||||
@@ -406,7 +405,7 @@ QUnit.module('Views', {
|
|||||||
// delete the a record
|
// delete the a record
|
||||||
|
|
||||||
await testUtils.dom.click(calendar.$('.fc-event:contains(event 4) .fc-content'));
|
await testUtils.dom.click(calendar.$('.fc-event:contains(event 4) .fc-content'));
|
||||||
await testUtils.dom.click($('.modal-footer button.btn:contains(Delete)'));
|
await testUtils.dom.click(calendar.$('.o_cw_popover .o_cw_popover_delete'));
|
||||||
assert.ok($('.modal-footer button.btn:contains(Ok)').length, "should display the confirm message");
|
assert.ok($('.modal-footer button.btn:contains(Ok)').length, "should display the confirm message");
|
||||||
await testUtils.dom.click($('.modal-footer button.btn:contains(Ok)'));
|
await testUtils.dom.click($('.modal-footer button.btn:contains(Ok)'));
|
||||||
assert.notOk(calendar.$('.fc-event:contains(event 4) .fc-content').length, "the record should be deleted");
|
assert.notOk(calendar.$('.fc-event:contains(event 4) .fc-content').length, "the record should be deleted");
|
||||||
@@ -435,10 +434,7 @@ QUnit.module('Views', {
|
|||||||
'date_start="start" '+
|
'date_start="start" '+
|
||||||
'date_stop="stop" '+
|
'date_stop="stop" '+
|
||||||
'all_day="allday" '+
|
'all_day="allday" '+
|
||||||
'mode="month" '+
|
'mode="month"/>',
|
||||||
'readonly_form_view_id="1">'+
|
|
||||||
'<field name="name"/>'+
|
|
||||||
'</calendar>',
|
|
||||||
archs: archs,
|
archs: archs,
|
||||||
viewOptions: {
|
viewOptions: {
|
||||||
initialDate: initialDate,
|
initialDate: initialDate,
|
||||||
@@ -497,8 +493,7 @@ QUnit.module('Views', {
|
|||||||
'date_start="start" '+
|
'date_start="start" '+
|
||||||
'date_stop="stop" '+
|
'date_stop="stop" '+
|
||||||
'all_day="allday" '+
|
'all_day="allday" '+
|
||||||
'mode="week" '+
|
'mode="week">'+
|
||||||
'readonly_form_view_id="1">'+
|
|
||||||
'<field name="name"/>'+
|
'<field name="name"/>'+
|
||||||
'<field name="start"/>'+
|
'<field name="start"/>'+
|
||||||
'<field name="allday"/>'+
|
'<field name="allday"/>'+
|
||||||
@@ -541,7 +536,7 @@ QUnit.module('Views', {
|
|||||||
|
|
||||||
testUtils.dom.triggerPositionalMouseEvent(left, top + 60, "mousemove");
|
testUtils.dom.triggerPositionalMouseEvent(left, top + 60, "mousemove");
|
||||||
|
|
||||||
assert.strictEqual(calendar.$('.fc-content .fc-time').text(), "08:00 - 10:00",
|
assert.strictEqual(calendar.$('.fc-content .fc-time').text(), "8:00 - 10:00",
|
||||||
"should display the time in the calendar sticker");
|
"should display the time in the calendar sticker");
|
||||||
|
|
||||||
await testUtils.dom.triggerPositionalMouseEvent(left, top + 60, "mouseup");
|
await testUtils.dom.triggerPositionalMouseEvent(left, top + 60, "mouseup");
|
||||||
@@ -550,8 +545,8 @@ QUnit.module('Views', {
|
|||||||
await testUtils.dom.click($('.modal button.btn:contains(Create)'));
|
await testUtils.dom.click($('.modal button.btn:contains(Create)'));
|
||||||
var $newevent = calendar.$('.fc-event:contains(new event)');
|
var $newevent = calendar.$('.fc-event:contains(new event)');
|
||||||
|
|
||||||
assert.strictEqual($newevent.text().replace(/[\s\n\r]+/g, ''), "08:00-10:00newevent12/13/201608:00:00False",
|
assert.strictEqual($newevent.find('.o_event_title').text(), "new event",
|
||||||
"should display the new event with time, title and additional fields");
|
"should display the new event with title");
|
||||||
|
|
||||||
assert.deepEqual($newevent.data('fcSeg').event.record,
|
assert.deepEqual($newevent.data('fcSeg').event.record,
|
||||||
{
|
{
|
||||||
@@ -567,7 +562,7 @@ QUnit.module('Views', {
|
|||||||
// delete record
|
// delete record
|
||||||
|
|
||||||
await testUtils.dom.click($newevent);
|
await testUtils.dom.click($newevent);
|
||||||
await testUtils.dom.click($('.modal button.btn-secondary:contains(Delete)'));
|
await testUtils.dom.click(calendar.$('.o_cw_popover .o_cw_popover_delete'));
|
||||||
await testUtils.dom.click($('.modal button.btn-primary:contains(Ok)'));
|
await testUtils.dom.click($('.modal button.btn-primary:contains(Ok)'));
|
||||||
assert.containsNone(calendar, '.fc-content', "should delete the record");
|
assert.containsNone(calendar, '.fc-content', "should delete the record");
|
||||||
|
|
||||||
@@ -595,7 +590,7 @@ QUnit.module('Views', {
|
|||||||
initialDate: initialDate,
|
initialDate: initialDate,
|
||||||
},
|
},
|
||||||
}).then(function (calendar) {
|
}).then(function (calendar) {
|
||||||
assert.strictEqual(calendar.$('.fc-day-header').first().text(), "Sun 12/11",
|
assert.strictEqual(calendar.$('.fc-day-header').first().text(), "Sun 11",
|
||||||
"The first day of the week should be Sunday");
|
"The first day of the week should be Sunday");
|
||||||
calendar.destroy();
|
calendar.destroy();
|
||||||
done();
|
done();
|
||||||
@@ -626,7 +621,7 @@ QUnit.module('Views', {
|
|||||||
week_start: 1,
|
week_start: 1,
|
||||||
},
|
},
|
||||||
}).then(function (calendar) {
|
}).then(function (calendar) {
|
||||||
assert.strictEqual(calendar.$('.fc-day-header').first().text(), "Mon 12/12",
|
assert.strictEqual(calendar.$('.fc-day-header').first().text(), "Mon 12",
|
||||||
"The first day of the week should be Monday");
|
"The first day of the week should be Monday");
|
||||||
calendar.destroy();
|
calendar.destroy();
|
||||||
done();
|
done();
|
||||||
@@ -659,15 +654,89 @@ QUnit.module('Views', {
|
|||||||
week_start: 7,
|
week_start: 7,
|
||||||
},
|
},
|
||||||
}).then(function (calendar) {
|
}).then(function (calendar) {
|
||||||
assert.strictEqual(calendar.$('.fc-week-number').text(), "W51",
|
assert.strictEqual(calendar.$('.fc-week-number').text(), "Week 51",
|
||||||
"We should be on the 51st week");
|
"We should be on the 51st week");
|
||||||
calendar.destroy();
|
calendar.destroy();
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
QUnit.test('render popover', async function (assert) {
|
||||||
|
assert.expect(14);
|
||||||
|
|
||||||
|
var calendar = await createCalendarView({
|
||||||
|
View: CalendarView,
|
||||||
|
model: 'event',
|
||||||
|
data: this.data,
|
||||||
|
arch:
|
||||||
|
'<calendar class="o_calendar_test" '+
|
||||||
|
'date_start="start" '+
|
||||||
|
'date_stop="stop" '+
|
||||||
|
'all_day="allday" '+
|
||||||
|
'mode="week">'+
|
||||||
|
'<field name="name" string="Custom Name"/>'+
|
||||||
|
'<field name="partner_id"/>'+
|
||||||
|
'</calendar>',
|
||||||
|
archs: archs,
|
||||||
|
viewOptions: {
|
||||||
|
initialDate: initialDate,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
await testUtils.dom.click($('.fc-event:contains(event 4)'));
|
||||||
|
|
||||||
|
assert.containsOnce(calendar, '.o_cw_popover', "should open a popover clicking on event");
|
||||||
|
assert.strictEqual(calendar.$('.o_cw_popover .popover-header').text(), 'event 4', "popover should have a title 'event 4'");
|
||||||
|
assert.containsOnce(calendar, '.o_cw_popover .o_cw_popover_edit', "popover should have an edit button");
|
||||||
|
assert.containsOnce(calendar, '.o_cw_popover .o_cw_popover_delete', "popover should have a delete button");
|
||||||
|
assert.containsOnce(calendar, '.o_cw_popover .o_cw_popover_close', "popover should have a close button");
|
||||||
|
|
||||||
|
assert.strictEqual(calendar.$('.o_cw_popover .list-group-item:first b.text-capitalize').text(), 'Wednesday, December 14, 2016', "should display date 'Wednesday, December 14, 2016'");
|
||||||
|
assert.containsN(calendar, '.o_cw_popover .o_cw_popover_fields_secondary .list-group-item', 2, "popover should have a two fields");
|
||||||
|
|
||||||
|
assert.containsOnce(calendar, '.o_cw_popover .o_cw_popover_fields_secondary .list-group-item:first .o_field_char', "should apply char widget");
|
||||||
|
assert.strictEqual(calendar.$('.o_cw_popover .o_cw_popover_fields_secondary .list-group-item:first strong').text(), 'Custom Name : ', "label should be a 'Custom Name'");
|
||||||
|
assert.strictEqual(calendar.$('.o_cw_popover .o_cw_popover_fields_secondary .list-group-item:first .o_field_char').text(), 'event 4', "value should be a 'event 4'");
|
||||||
|
|
||||||
|
assert.containsOnce(calendar, '.o_cw_popover .o_cw_popover_fields_secondary .list-group-item:last .o_form_uri', "should apply m20 widget");
|
||||||
|
assert.strictEqual(calendar.$('.o_cw_popover .o_cw_popover_fields_secondary .list-group-item:last strong').text(), 'user : ', "label should be a 'user'");
|
||||||
|
assert.strictEqual(calendar.$('.o_cw_popover .o_cw_popover_fields_secondary .list-group-item:last .o_form_uri').text(), 'partner 1', "value should be a 'partner 1'");
|
||||||
|
|
||||||
|
await testUtils.dom.click($('.o_cw_popover .o_cw_popover_close'));
|
||||||
|
assert.containsNone(calendar, '.o_cw_popover', "should close a popover");
|
||||||
|
|
||||||
|
calendar.destroy();
|
||||||
|
});
|
||||||
|
|
||||||
|
QUnit.test('attributes hide_date and hide_time', async function (assert) {
|
||||||
|
assert.expect(1);
|
||||||
|
|
||||||
|
var calendar = await createCalendarView({
|
||||||
|
View: CalendarView,
|
||||||
|
model: 'event',
|
||||||
|
data: this.data,
|
||||||
|
arch:
|
||||||
|
'<calendar class="o_calendar_test" '+
|
||||||
|
'date_start="start" '+
|
||||||
|
'date_stop="stop" '+
|
||||||
|
'hide_date="true" '+
|
||||||
|
'hide_time="true" '+
|
||||||
|
'mode="month">'+
|
||||||
|
'</calendar>',
|
||||||
|
archs: archs,
|
||||||
|
viewOptions: {
|
||||||
|
initialDate: initialDate,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
await testUtils.dom.click($('.fc-event:contains(event 4)'));
|
||||||
|
assert.containsNone(calendar, '.o_cw_popover .list-group-item', "popover should not contain date/time");
|
||||||
|
|
||||||
|
calendar.destroy();
|
||||||
|
});
|
||||||
|
|
||||||
QUnit.test('create event with timezone in week mode with formViewDialog European locale', async function (assert) {
|
QUnit.test('create event with timezone in week mode with formViewDialog European locale', async function (assert) {
|
||||||
assert.expect(8);
|
assert.expect(7);
|
||||||
|
|
||||||
this.data.event.records = [];
|
this.data.event.records = [];
|
||||||
this.data.event.onchanges = {
|
this.data.event.onchanges = {
|
||||||
@@ -692,8 +761,7 @@ QUnit.module('Views', {
|
|||||||
'date_start="start" '+
|
'date_start="start" '+
|
||||||
'date_stop="stop" '+
|
'date_stop="stop" '+
|
||||||
'all_day="allday" '+
|
'all_day="allday" '+
|
||||||
'mode="week" '+
|
'mode="week">'+
|
||||||
'readonly_form_view_id="1">'+
|
|
||||||
'<field name="name"/>'+
|
'<field name="name"/>'+
|
||||||
'</calendar>',
|
'</calendar>',
|
||||||
archs: archs,
|
archs: archs,
|
||||||
@@ -771,8 +839,8 @@ QUnit.module('Views', {
|
|||||||
await testUtils.dom.click($('.modal-lg button.btn:contains(Save)'));
|
await testUtils.dom.click($('.modal-lg button.btn:contains(Save)'));
|
||||||
var $newevent = calendar.$('.fc-event:contains(new event)');
|
var $newevent = calendar.$('.fc-event:contains(new event)');
|
||||||
|
|
||||||
assert.strictEqual($newevent.text().replace(/[\s\n\r]+/g, ''), "08:00-10:00newevent",
|
assert.strictEqual($newevent.find('.o_event_title').text(), "new event",
|
||||||
"should display the new event with time and title");
|
"should display the new event with title");
|
||||||
|
|
||||||
assert.deepEqual($newevent.data('fcSeg').event.record,
|
assert.deepEqual($newevent.data('fcSeg').event.record,
|
||||||
{
|
{
|
||||||
@@ -831,8 +899,7 @@ QUnit.module('Views', {
|
|||||||
'date_start="start" '+
|
'date_start="start" '+
|
||||||
'date_stop="stop" '+
|
'date_stop="stop" '+
|
||||||
'all_day="allday" '+
|
'all_day="allday" '+
|
||||||
'mode="week" '+
|
'mode="week">'+
|
||||||
'readonly_form_view_id="1">'+
|
|
||||||
'<field name="name"/>'+
|
'<field name="name"/>'+
|
||||||
'<field name="start"/>'+
|
'<field name="start"/>'+
|
||||||
'<field name="allday"/>'+
|
'<field name="allday"/>'+
|
||||||
@@ -875,7 +942,7 @@ QUnit.module('Views', {
|
|||||||
|
|
||||||
testUtils.dom.triggerPositionalMouseEvent(left, top + 60, "mousemove");
|
testUtils.dom.triggerPositionalMouseEvent(left, top + 60, "mousemove");
|
||||||
|
|
||||||
assert.strictEqual(calendar.$('.fc-content .fc-time').text(), "8:00am - 10:00am",
|
assert.strictEqual(calendar.$('.fc-content .fc-time').text(), "8:00 - 10:00",
|
||||||
"should display the time in the calendar sticker");
|
"should display the time in the calendar sticker");
|
||||||
|
|
||||||
testUtils.dom.triggerPositionalMouseEvent(left, top + 60, "mouseup");
|
testUtils.dom.triggerPositionalMouseEvent(left, top + 60, "mouseup");
|
||||||
@@ -884,8 +951,8 @@ QUnit.module('Views', {
|
|||||||
await testUtils.dom.click($('.modal button.btn:contains(Create)'));
|
await testUtils.dom.click($('.modal button.btn:contains(Create)'));
|
||||||
var $newevent = calendar.$('.fc-event:contains(new event)');
|
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",
|
assert.strictEqual($newevent.find('.o_event_title').text(), "new event",
|
||||||
"should display the new event with time, title and additional fields");
|
"should display the new event with title");
|
||||||
|
|
||||||
assert.deepEqual($newevent.data('fcSeg').event.record,
|
assert.deepEqual($newevent.data('fcSeg').event.record,
|
||||||
{
|
{
|
||||||
@@ -901,7 +968,7 @@ QUnit.module('Views', {
|
|||||||
// delete record
|
// delete record
|
||||||
|
|
||||||
await testUtils.dom.click($newevent);
|
await testUtils.dom.click($newevent);
|
||||||
await testUtils.dom.click($('.modal button.btn-secondary:contains(Delete)'));
|
await testUtils.dom.click(calendar.$('.o_cw_popover .o_cw_popover_delete'));
|
||||||
await testUtils.dom.click($('.modal button.btn-primary:contains(Ok)'));
|
await testUtils.dom.click($('.modal button.btn-primary:contains(Ok)'));
|
||||||
assert.containsNone(calendar, '.fc-content', "should delete the record");
|
assert.containsNone(calendar, '.fc-content', "should delete the record");
|
||||||
|
|
||||||
@@ -909,7 +976,7 @@ QUnit.module('Views', {
|
|||||||
});
|
});
|
||||||
|
|
||||||
QUnit.test('create event with timezone in week mode with formViewDialog American locale', async function (assert) {
|
QUnit.test('create event with timezone in week mode with formViewDialog American locale', async function (assert) {
|
||||||
assert.expect(8);
|
assert.expect(7);
|
||||||
|
|
||||||
this.data.event.records = [];
|
this.data.event.records = [];
|
||||||
this.data.event.onchanges = {
|
this.data.event.onchanges = {
|
||||||
@@ -934,8 +1001,7 @@ QUnit.module('Views', {
|
|||||||
'date_start="start" '+
|
'date_start="start" '+
|
||||||
'date_stop="stop" '+
|
'date_stop="stop" '+
|
||||||
'all_day="allday" '+
|
'all_day="allday" '+
|
||||||
'mode="week" '+
|
'mode="week">'+
|
||||||
'readonly_form_view_id="1">'+
|
|
||||||
'<field name="name"/>'+
|
'<field name="name"/>'+
|
||||||
'</calendar>',
|
'</calendar>',
|
||||||
archs: archs,
|
archs: archs,
|
||||||
@@ -1013,8 +1079,8 @@ QUnit.module('Views', {
|
|||||||
await testUtils.dom.click($('.modal-lg button.btn:contains(Save)'));
|
await testUtils.dom.click($('.modal-lg button.btn:contains(Save)'));
|
||||||
var $newevent = calendar.$('.fc-event:contains(new event)');
|
var $newevent = calendar.$('.fc-event:contains(new event)');
|
||||||
|
|
||||||
assert.strictEqual($newevent.text().replace(/[\s\n\r]+/g, ''), "8:00am-10:00amnewevent",
|
assert.strictEqual($newevent.find('.o_event_title').text(), "new event",
|
||||||
"should display the new event with time and title");
|
"should display the new event with title");
|
||||||
|
|
||||||
assert.deepEqual($newevent.data('fcSeg').event.record,
|
assert.deepEqual($newevent.data('fcSeg').event.record,
|
||||||
{
|
{
|
||||||
@@ -1058,7 +1124,7 @@ QUnit.module('Views', {
|
|||||||
calendar.destroy();
|
calendar.destroy();
|
||||||
});
|
});
|
||||||
|
|
||||||
QUnit.test('check calendar week column timeformat and event content timeformat', async function (assert) {
|
QUnit.test('check calendar week column timeformat', async function (assert) {
|
||||||
assert.expect(2);
|
assert.expect(2);
|
||||||
|
|
||||||
var calendar = await createCalendarView({
|
var calendar = await createCalendarView({
|
||||||
@@ -1066,9 +1132,7 @@ QUnit.module('Views', {
|
|||||||
model: 'event',
|
model: 'event',
|
||||||
data: this.data,
|
data: this.data,
|
||||||
arch:
|
arch:
|
||||||
'<calendar date_start="start">'+
|
'<calendar date_start="start"/>',
|
||||||
'<field name="name"/>'+
|
|
||||||
'</calendar>',
|
|
||||||
archs: archs,
|
archs: archs,
|
||||||
viewOptions: {
|
viewOptions: {
|
||||||
initialDate: initialDate,
|
initialDate: initialDate,
|
||||||
@@ -1079,7 +1143,7 @@ QUnit.module('Views', {
|
|||||||
});
|
});
|
||||||
|
|
||||||
assert.strictEqual(calendar.$('.fc-axis:contains(8am)').length, 1, "calendar should show according to timeformat");
|
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,
|
assert.strictEqual(calendar.$('.fc-axis:contains(11pm)').length, 1,
|
||||||
"event time format should 12 hour");
|
"event time format should 12 hour");
|
||||||
|
|
||||||
calendar.destroy();
|
calendar.destroy();
|
||||||
@@ -1100,8 +1164,7 @@ QUnit.module('Views', {
|
|||||||
'date_start="start" '+
|
'date_start="start" '+
|
||||||
'date_stop="stop" '+
|
'date_stop="stop" '+
|
||||||
'all_day="allday" '+
|
'all_day="allday" '+
|
||||||
'mode="week" '+
|
'mode="week">'+
|
||||||
'readonly_form_view_id="1">'+
|
|
||||||
'<field name="name"/>'+
|
'<field name="name"/>'+
|
||||||
'</calendar>',
|
'</calendar>',
|
||||||
archs: archs,
|
archs: archs,
|
||||||
@@ -1164,10 +1227,7 @@ QUnit.module('Views', {
|
|||||||
'date_start="start" '+
|
'date_start="start" '+
|
||||||
'date_stop="stop" '+
|
'date_stop="stop" '+
|
||||||
'mode="week" '+
|
'mode="week" '+
|
||||||
'quick_add="False" '+
|
'quick_add="False"/>',
|
||||||
'readonly_form_view_id="1">'+
|
|
||||||
'<field name="name"/>'+
|
|
||||||
'</calendar>',
|
|
||||||
archs: archs,
|
archs: archs,
|
||||||
viewOptions: {
|
viewOptions: {
|
||||||
initialDate: initialDate,
|
initialDate: initialDate,
|
||||||
@@ -1217,8 +1277,7 @@ QUnit.module('Views', {
|
|||||||
'event_open_popup="true" '+
|
'event_open_popup="true" '+
|
||||||
'date_start="start" '+
|
'date_start="start" '+
|
||||||
'date_stop="stop" '+
|
'date_stop="stop" '+
|
||||||
'mode="month" '+
|
'mode="month">'+
|
||||||
'readonly_form_view_id="1">'+
|
|
||||||
'<field name="name"/>'+
|
'<field name="name"/>'+
|
||||||
'</calendar>',
|
'</calendar>',
|
||||||
archs: archs,
|
archs: archs,
|
||||||
@@ -1243,14 +1302,14 @@ QUnit.module('Views', {
|
|||||||
},
|
},
|
||||||
}, {positionalClicks: true});
|
}, {positionalClicks: true});
|
||||||
|
|
||||||
var pos = calendar.$('.fc-bg td:eq(20)').offset();
|
var pos = calendar.$('.fc-bg td:eq(17)').offset();
|
||||||
try {
|
try {
|
||||||
testUtils.dom.triggerPositionalMouseEvent(pos.left+15, pos.top+15, "mousedown");
|
testUtils.dom.triggerPositionalMouseEvent(pos.left+15, pos.top+15, "mousedown");
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
calendar.destroy();
|
calendar.destroy();
|
||||||
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.');
|
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.');
|
||||||
}
|
}
|
||||||
pos = calendar.$('.fc-bg td:eq(21)').offset();
|
pos = calendar.$('.fc-bg td:eq(18)').offset();
|
||||||
testUtils.dom.triggerPositionalMouseEvent(pos.left+15, pos.top+15, "mousemove");
|
testUtils.dom.triggerPositionalMouseEvent(pos.left+15, pos.top+15, "mousemove");
|
||||||
testUtils.dom.triggerPositionalMouseEvent(pos.left+15, pos.top+15, "mouseup");
|
testUtils.dom.triggerPositionalMouseEvent(pos.left+15, pos.top+15, "mouseup");
|
||||||
await testUtils.nextTick();
|
await testUtils.nextTick();
|
||||||
@@ -1288,10 +1347,7 @@ QUnit.module('Views', {
|
|||||||
'date_start="start" '+
|
'date_start="start" '+
|
||||||
'date_stop="stop" '+
|
'date_stop="stop" '+
|
||||||
'all_day="allday" '+
|
'all_day="allday" '+
|
||||||
'mode="week" '+
|
'mode="week"/>',
|
||||||
'readonly_form_view_id="1">'+
|
|
||||||
'<field name="name"/>'+
|
|
||||||
'</calendar>',
|
|
||||||
archs: archs,
|
archs: archs,
|
||||||
viewOptions: {
|
viewOptions: {
|
||||||
initialDate: initialDate,
|
initialDate: initialDate,
|
||||||
@@ -1344,7 +1400,7 @@ QUnit.module('Views', {
|
|||||||
'date_start="start" '+
|
'date_start="start" '+
|
||||||
'date_stop="stop" '+
|
'date_stop="stop" '+
|
||||||
'all_day="allday"> '+
|
'all_day="allday"> '+
|
||||||
'<field name="partner_ids" avatar_field="image" write_model="filter_partner" write_field="partner_id"/>'+
|
'<field name="partner_ids" widget="many2many_tags_avatar" avatar_field="image" write_model="filter_partner" write_field="partner_id"/>'+
|
||||||
'</calendar>',
|
'</calendar>',
|
||||||
archs: archs,
|
archs: archs,
|
||||||
viewOptions: {
|
viewOptions: {
|
||||||
@@ -1352,18 +1408,19 @@ QUnit.module('Views', {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
assert.containsN(calendar, '.o_calendar_filter_items .o_cal_avatar', 3,
|
assert.containsN(calendar, '.o_calendar_filter_items .o_cw_filter_avatar', 3,
|
||||||
"should have 3 avatars in the side bar");
|
"should have 3 avatars in the side bar");
|
||||||
|
|
||||||
var $event1Avatars = calendar.$('.fc-event .o_calendar_avatars').first();
|
// Event 1
|
||||||
assert.containsOnce($event1Avatars, 'img', "should have 1 avatar");
|
await testUtils.dom.click(calendar.$('.fc-event:first'));
|
||||||
assert.containsNone($event1Avatars, 'span',
|
assert.ok(calendar.$('.o_cw_popover').length, "should open a popover clicking on event");
|
||||||
"should not have a span for more attendees since there is only one");
|
assert.strictEqual(calendar.$('.o_cw_popover').find('img').length, 1, "should have 1 avatar");
|
||||||
|
|
||||||
|
// Event 2
|
||||||
|
await testUtils.dom.click(calendar.$('.fc-event:eq(1)'));
|
||||||
|
assert.ok(calendar.$('.o_cw_popover').length, "should open a popover clicking on event");
|
||||||
|
assert.strictEqual(calendar.$('.o_cw_popover').find('img').length, 5, "should have 5 avatar");
|
||||||
|
|
||||||
var $event2Avatars = calendar.$('.fc-event:contains(All day) .o_calendar_avatars');
|
|
||||||
assert.containsN($event2Avatars, 'img', 3, "should have 3 avatars");
|
|
||||||
assert.strictEqual($event2Avatars.find('span').text(), '+2',
|
|
||||||
"should indicate there are 2 more attendees that we don't show");
|
|
||||||
calendar.destroy();
|
calendar.destroy();
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -1380,10 +1437,7 @@ QUnit.module('Views', {
|
|||||||
'date_start="start" '+
|
'date_start="start" '+
|
||||||
'date_stop="stop" '+
|
'date_stop="stop" '+
|
||||||
'all_day="allday" '+
|
'all_day="allday" '+
|
||||||
'mode="month" '+
|
'mode="month"/>',
|
||||||
'readonly_form_view_id="1">'+
|
|
||||||
'<field name="name"/>'+
|
|
||||||
'</calendar>',
|
|
||||||
archs: archs,
|
archs: archs,
|
||||||
viewOptions: {
|
viewOptions: {
|
||||||
initialDate: initialDate,
|
initialDate: initialDate,
|
||||||
@@ -1411,6 +1465,7 @@ QUnit.module('Views', {
|
|||||||
"should open the form view");
|
"should open the form view");
|
||||||
});
|
});
|
||||||
await testUtils.dom.click(calendar.$('.fc-event:contains(event 4) .fc-content'));
|
await testUtils.dom.click(calendar.$('.fc-event:contains(event 4) .fc-content'));
|
||||||
|
await testUtils.dom.click(calendar.$('.o_cw_popover .o_cw_popover_edit'));
|
||||||
|
|
||||||
// create a new event and edit it
|
// create a new event and edit it
|
||||||
|
|
||||||
@@ -1456,10 +1511,7 @@ QUnit.module('Views', {
|
|||||||
'string="Events" ' +
|
'string="Events" ' +
|
||||||
'date_start="start" '+
|
'date_start="start" '+
|
||||||
'date_stop="stop" '+
|
'date_stop="stop" '+
|
||||||
'mode="month" '+
|
'mode="month"/>',
|
||||||
'readonly_form_view_id="1">'+
|
|
||||||
'<field name="name"/>'+
|
|
||||||
'</calendar>',
|
|
||||||
archs: archs,
|
archs: archs,
|
||||||
viewOptions: {
|
viewOptions: {
|
||||||
initialDate: initialDate,
|
initialDate: initialDate,
|
||||||
@@ -1515,10 +1567,7 @@ QUnit.module('Views', {
|
|||||||
'date_start="start" '+
|
'date_start="start" '+
|
||||||
'date_stop="stop" '+
|
'date_stop="stop" '+
|
||||||
'all_day="allday" '+
|
'all_day="allday" '+
|
||||||
'mode="month" '+
|
'mode="month"/>',
|
||||||
'readonly_form_view_id="1">'+
|
|
||||||
'<field name="name"/>'+
|
|
||||||
'</calendar>',
|
|
||||||
archs: archs,
|
archs: archs,
|
||||||
viewOptions: {
|
viewOptions: {
|
||||||
initialDate: initialDate,
|
initialDate: initialDate,
|
||||||
@@ -1548,6 +1597,7 @@ QUnit.module('Views', {
|
|||||||
"should open the form view");
|
"should open the form view");
|
||||||
});
|
});
|
||||||
await testUtils.dom.click(calendar.$('.fc-event:contains(event 4) .fc-content'));
|
await testUtils.dom.click(calendar.$('.fc-event:contains(event 4) .fc-content'));
|
||||||
|
await testUtils.dom.click(calendar.$('.o_cw_popover .o_cw_popover_edit'));
|
||||||
|
|
||||||
// create a new event and edit it
|
// create a new event and edit it
|
||||||
|
|
||||||
@@ -1610,7 +1660,6 @@ QUnit.module('Views', {
|
|||||||
'mode="week" '+
|
'mode="week" '+
|
||||||
'attendee="partner_ids" '+
|
'attendee="partner_ids" '+
|
||||||
'color="partner_id">'+
|
'color="partner_id">'+
|
||||||
'<field name="name"/>'+
|
|
||||||
'<filter name="user_id" avatar_field="image"/>'+
|
'<filter name="user_id" avatar_field="image"/>'+
|
||||||
'<field name="partner_ids" write_model="filter_partner" write_field="partner_id"/>'+
|
'<field name="partner_ids" write_model="filter_partner" write_field="partner_id"/>'+
|
||||||
'</calendar>',
|
'</calendar>',
|
||||||
@@ -1662,7 +1711,6 @@ QUnit.module('Views', {
|
|||||||
'mode="week" '+
|
'mode="week" '+
|
||||||
'attendee="partner_ids" '+
|
'attendee="partner_ids" '+
|
||||||
'color="partner_id">'+
|
'color="partner_id">'+
|
||||||
'<field name="name"/>'+
|
|
||||||
'<filter name="user_id" avatar_field="image"/>'+
|
'<filter name="user_id" avatar_field="image"/>'+
|
||||||
'<field name="partner_ids" write_model="filter_partner" write_field="partner_id"/>'+
|
'<field name="partner_ids" write_model="filter_partner" write_field="partner_id"/>'+
|
||||||
'</calendar>',
|
'</calendar>',
|
||||||
@@ -1745,7 +1793,6 @@ QUnit.module('Views', {
|
|||||||
'mode="week" '+
|
'mode="week" '+
|
||||||
'attendee="partner_ids" '+
|
'attendee="partner_ids" '+
|
||||||
'color="partner_id">'+
|
'color="partner_id">'+
|
||||||
'<field name="name"/>'+
|
|
||||||
'<filter name="user_id" avatar_field="image"/>'+
|
'<filter name="user_id" avatar_field="image"/>'+
|
||||||
'<field name="partner_ids" write_model="filter_partner" write_field="partner_id"/>'+
|
'<field name="partner_ids" write_model="filter_partner" write_field="partner_id"/>'+
|
||||||
'</calendar>',
|
'</calendar>',
|
||||||
@@ -1797,7 +1844,7 @@ QUnit.module('Views', {
|
|||||||
});
|
});
|
||||||
|
|
||||||
QUnit.test('Update event with filters', async function (assert) {
|
QUnit.test('Update event with filters', async function (assert) {
|
||||||
assert.expect(4);
|
assert.expect(5);
|
||||||
|
|
||||||
var records = this.data.user.records;
|
var records = this.data.user.records;
|
||||||
records.push({
|
records.push({
|
||||||
@@ -1825,7 +1872,6 @@ QUnit.module('Views', {
|
|||||||
'mode="week" '+
|
'mode="week" '+
|
||||||
'attendee="partner_ids" '+
|
'attendee="partner_ids" '+
|
||||||
'color="partner_id">'+
|
'color="partner_id">'+
|
||||||
'<field name="name"/>'+
|
|
||||||
'<filter name="user_id" avatar_field="image"/>'+
|
'<filter name="user_id" avatar_field="image"/>'+
|
||||||
'<field name="partner_ids" write_model="filter_partner" write_field="partner_id"/>'+
|
'<field name="partner_ids" write_model="filter_partner" write_field="partner_id"/>'+
|
||||||
'</calendar>',
|
'</calendar>',
|
||||||
@@ -1852,7 +1898,8 @@ QUnit.module('Views', {
|
|||||||
assert.containsN(calendar, '.fc-event', 3, "should display 3 events");
|
assert.containsN(calendar, '.fc-event', 3, "should display 3 events");
|
||||||
|
|
||||||
await testUtils.dom.click(calendar.$('.fc-event:contains(event 2) .fc-content'));
|
await testUtils.dom.click(calendar.$('.fc-event:contains(event 2) .fc-content'));
|
||||||
await testUtils.dom.click($('.modal button.btn:contains(Edit)'));
|
assert.ok(calendar.$('.o_cw_popover').length, "should open a popover clicking on event");
|
||||||
|
await testUtils.dom.click(calendar.$('.o_cw_popover .o_cw_popover_edit'));
|
||||||
await testUtils.dom.click($('.modal .o_field_widget[name="user_id"] input'));
|
await testUtils.dom.click($('.modal .o_field_widget[name="user_id"] input'));
|
||||||
await testUtils.dom.click($('.ui-menu-item a:contains(user 5)').trigger('mouseenter'));
|
await testUtils.dom.click($('.ui-menu-item a:contains(user 5)').trigger('mouseenter'));
|
||||||
await testUtils.dom.click($('.modal button.btn:contains(Save)'));
|
await testUtils.dom.click($('.modal button.btn:contains(Save)'));
|
||||||
@@ -1916,7 +1963,6 @@ QUnit.module('Views', {
|
|||||||
'mode="week" '+
|
'mode="week" '+
|
||||||
'attendee="partner_ids" '+
|
'attendee="partner_ids" '+
|
||||||
'color="partner_id">'+
|
'color="partner_id">'+
|
||||||
'<field name="name"/>'+
|
|
||||||
'<filter name="user_id" avatar_field="image"/>'+
|
'<filter name="user_id" avatar_field="image"/>'+
|
||||||
'<field name="partner_ids" write_model="filter_partner" write_field="partner_id"/>'+
|
'<field name="partner_ids" write_model="filter_partner" write_field="partner_id"/>'+
|
||||||
'</calendar>',
|
'</calendar>',
|
||||||
@@ -1930,7 +1976,7 @@ QUnit.module('Views', {
|
|||||||
|
|
||||||
assert.containsN(calendar, '.o_calendar_filter_item', 6, "should display 6 filter items");
|
assert.containsN(calendar, '.o_calendar_filter_item', 6, "should display 6 filter items");
|
||||||
assert.containsN(calendar, '.fc-event', 2, "should display 2 events");
|
assert.containsN(calendar, '.fc-event', 2, "should display 2 events");
|
||||||
assert.strictEqual(calendar.$('.fc-event .o_field_name').text().replace(/\s/g, ''), "event7event8",
|
assert.strictEqual(calendar.$('.fc-event .o_event_title').text().replace(/\s/g, ''), "event7event8",
|
||||||
"should display 2 events");
|
"should display 2 events");
|
||||||
|
|
||||||
calendar.destroy();
|
calendar.destroy();
|
||||||
@@ -2021,7 +2067,6 @@ QUnit.module('Views', {
|
|||||||
'mode="week" '+
|
'mode="week" '+
|
||||||
'attendee="partner_ids" '+
|
'attendee="partner_ids" '+
|
||||||
'color="partner_id">'+
|
'color="partner_id">'+
|
||||||
'<field name="name"/>'+
|
|
||||||
'<filter name="user_id" avatar_field="image"/>'+
|
'<filter name="user_id" avatar_field="image"/>'+
|
||||||
'<field name="partner_ids" write_model="filter_partner" write_field="partner_id"/>'+
|
'<field name="partner_ids" write_model="filter_partner" write_field="partner_id"/>'+
|
||||||
'</calendar>',
|
'</calendar>',
|
||||||
@@ -2056,10 +2101,7 @@ QUnit.module('Views', {
|
|||||||
'date_start="start" '+
|
'date_start="start" '+
|
||||||
'date_stop="stop" '+
|
'date_stop="stop" '+
|
||||||
'all_day="allday" '+
|
'all_day="allday" '+
|
||||||
'mode="month" '+
|
'mode="month"/>',
|
||||||
'readonly_form_view_id="1">'+
|
|
||||||
'<field name="name"/>'+
|
|
||||||
'</calendar>',
|
|
||||||
archs: archs,
|
archs: archs,
|
||||||
viewOptions: {
|
viewOptions: {
|
||||||
initialDate: initialDate,
|
initialDate: initialDate,
|
||||||
@@ -2126,7 +2168,6 @@ QUnit.module('Views', {
|
|||||||
'mode="week" '+
|
'mode="week" '+
|
||||||
'attendee="partner_ids" '+
|
'attendee="partner_ids" '+
|
||||||
'color="partner_id">'+
|
'color="partner_id">'+
|
||||||
'<field name="name"/>'+
|
|
||||||
'<filter name="user_id" avatar_field="image"/>'+
|
'<filter name="user_id" avatar_field="image"/>'+
|
||||||
'<field name="partner_ids" write_model="filter_partner" write_field="partner_id"/>'+
|
'<field name="partner_ids" write_model="filter_partner" write_field="partner_id"/>'+
|
||||||
'</calendar>',
|
'</calendar>',
|
||||||
@@ -2178,10 +2219,7 @@ QUnit.module('Views', {
|
|||||||
'date_start="start" '+
|
'date_start="start" '+
|
||||||
'date_stop="stop" '+
|
'date_stop="stop" '+
|
||||||
'all_day="allday" '+
|
'all_day="allday" '+
|
||||||
'mode="month" '+
|
'mode="month"/>',
|
||||||
'readonly_form_view_id="1">'+
|
|
||||||
'<field name="name"/>'+
|
|
||||||
'</calendar>',
|
|
||||||
archs: archs,
|
archs: archs,
|
||||||
viewOptions: {
|
viewOptions: {
|
||||||
initialDate: initialDate,
|
initialDate: initialDate,
|
||||||
@@ -2216,9 +2254,7 @@ QUnit.module('Views', {
|
|||||||
'event,1,calendar': '<calendar class="o_calendar_test" '+
|
'event,1,calendar': '<calendar class="o_calendar_test" '+
|
||||||
'date_start="start" '+
|
'date_start="start" '+
|
||||||
'date_stop="stop" '+
|
'date_stop="stop" '+
|
||||||
'all_day="allday"> '+
|
'all_day="allday"/>',
|
||||||
'<field name="name"/>'+
|
|
||||||
'</calendar>',
|
|
||||||
'event,false,search': '<search></search>',
|
'event,false,search': '<search></search>',
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -2250,9 +2286,7 @@ QUnit.module('Views', {
|
|||||||
model: 'event',
|
model: 'event',
|
||||||
data: this.data,
|
data: this.data,
|
||||||
arch:
|
arch:
|
||||||
'<calendar date_start="start_date">'+
|
'<calendar date_start="start_date"/>',
|
||||||
'<field name="name"/>'+
|
|
||||||
'</calendar>',
|
|
||||||
archs: archs,
|
archs: archs,
|
||||||
viewOptions: {
|
viewOptions: {
|
||||||
initialDate: initialDate,
|
initialDate: initialDate,
|
||||||
@@ -2278,7 +2312,7 @@ QUnit.module('Views', {
|
|||||||
});
|
});
|
||||||
|
|
||||||
QUnit.test('timezone does not affect drag and drop', async function (assert) {
|
QUnit.test('timezone does not affect drag and drop', async function (assert) {
|
||||||
assert.expect(6);
|
assert.expect(10);
|
||||||
|
|
||||||
var calendar = await createCalendarView({
|
var calendar = await createCalendarView({
|
||||||
View: CalendarView,
|
View: CalendarView,
|
||||||
@@ -2308,12 +2342,13 @@ QUnit.module('Views', {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
var events = calendar.$('.fc-event').map(function () {
|
assert.strictEqual(calendar.$('.fc-event:eq(0)').text().trim(), "event 1");
|
||||||
return $(this).text().trim().replace(/\s+/g, '|');
|
await testUtils.dom.click(calendar.$('.fc-event:eq(0)'));
|
||||||
});
|
assert.strictEqual(calendar.$('.o_field_widget[name="start"]').text(), "12/09/2016 08:00:00");
|
||||||
|
|
||||||
assert.strictEqual(events[0], "event|1|12/09/2016|08:00:00");
|
assert.strictEqual(calendar.$('.fc-event:eq(5)').text().trim(), "event 6");
|
||||||
assert.strictEqual(events[5], "event|6|12/16/2016|16:00:00");
|
await testUtils.dom.click(calendar.$('.fc-event:eq(5)'));
|
||||||
|
assert.strictEqual(calendar.$('.o_field_widget[name="start"]').text(), "12/16/2016 16:00:00");
|
||||||
|
|
||||||
// Move event 6 as on first day of month view (27th november 2016)
|
// Move event 6 as on first day of month view (27th november 2016)
|
||||||
await testUtils.dragAndDrop(
|
await testUtils.dragAndDrop(
|
||||||
@@ -2322,18 +2357,19 @@ QUnit.module('Views', {
|
|||||||
);
|
);
|
||||||
await testUtils.nextTick();
|
await testUtils.nextTick();
|
||||||
|
|
||||||
events = calendar.$('.fc-event').map(function () {
|
assert.strictEqual(calendar.$('.fc-event:eq(0)').text().trim(), "event 6");
|
||||||
return $(this).text().trim().replace(/\s+/g, '|');
|
await testUtils.dom.click(calendar.$('.fc-event:eq(0)'));
|
||||||
});
|
assert.strictEqual(calendar.$('.o_field_widget[name="start"]').text(), "11/27/2016 16:00:00");
|
||||||
|
|
||||||
assert.strictEqual(events[0], "event|6|11/27/2016|16:00:00");
|
assert.strictEqual(calendar.$('.fc-event:eq(1)').text().trim(), "event 1");
|
||||||
assert.strictEqual(events[1], "event|1|12/09/2016|08:00:00");
|
await testUtils.dom.click(calendar.$('.fc-event:eq(1)'));
|
||||||
|
assert.strictEqual(calendar.$('.o_field_widget[name="start"]').text(), "12/09/2016 08:00:00");
|
||||||
|
|
||||||
calendar.destroy();
|
calendar.destroy();
|
||||||
});
|
});
|
||||||
|
|
||||||
QUnit.test('timzeone does not affect calendar with date field', async function (assert) {
|
QUnit.test('timzeone does not affect calendar with date field', async function (assert) {
|
||||||
assert.expect(8);
|
assert.expect(11);
|
||||||
|
|
||||||
var calendar = await createCalendarView({
|
var calendar = await createCalendarView({
|
||||||
View: CalendarView,
|
View: CalendarView,
|
||||||
@@ -2374,7 +2410,9 @@ QUnit.module('Views', {
|
|||||||
await testUtils.dom.click($('.modal button.btn:contains(Create)'));
|
await testUtils.dom.click($('.modal button.btn:contains(Create)'));
|
||||||
await testUtils.nextTick();
|
await testUtils.nextTick();
|
||||||
|
|
||||||
assert.strictEqual(calendar.$('.o_field_start_date').text().trim(), "12/20/2016");
|
await testUtils.dom.click(calendar.$('.fc-event:contains(An event)'));
|
||||||
|
assert.ok(calendar.$('.o_cw_popover').length, "should open a popover clicking on event");
|
||||||
|
assert.strictEqual(calendar.$('.o_cw_popover .o_cw_popover_fields_secondary .list-group-item:last .o_field_date').text(), '12/20/2016', "should have correct start date");
|
||||||
|
|
||||||
// Move event to another day (on 27 november)
|
// Move event to another day (on 27 november)
|
||||||
await testUtils.dragAndDrop(
|
await testUtils.dragAndDrop(
|
||||||
@@ -2383,7 +2421,9 @@ QUnit.module('Views', {
|
|||||||
);
|
);
|
||||||
await testUtils.nextTick();
|
await testUtils.nextTick();
|
||||||
assert.verifySteps(["2016-11-27 00:00:00"]);
|
assert.verifySteps(["2016-11-27 00:00:00"]);
|
||||||
assert.strictEqual(calendar.$('.o_field_start_date').text().trim(), "11/27/2016");
|
await testUtils.dom.click(calendar.$('.fc-event:contains(An event)'));
|
||||||
|
assert.ok(calendar.$('.o_cw_popover').length, "should open a popover clicking on event");
|
||||||
|
assert.strictEqual(calendar.$('.o_cw_popover .o_cw_popover_fields_secondary .list-group-item:last .o_field_date').text(), '11/27/2016', "should have correct start date");
|
||||||
|
|
||||||
// Move event to last day (on 7 january)
|
// Move event to last day (on 7 january)
|
||||||
await testUtils.dragAndDrop(
|
await testUtils.dragAndDrop(
|
||||||
@@ -2392,7 +2432,9 @@ QUnit.module('Views', {
|
|||||||
);
|
);
|
||||||
await testUtils.nextTick();
|
await testUtils.nextTick();
|
||||||
assert.verifySteps(["2017-01-07 00:00:00"]);
|
assert.verifySteps(["2017-01-07 00:00:00"]);
|
||||||
assert.strictEqual(calendar.$('.o_field_start_date').text().trim(), "01/07/2017");
|
await testUtils.dom.click(calendar.$('.fc-event:contains(An event)'));
|
||||||
|
assert.ok(calendar.$('.o_cw_popover').length, "should open a popover clicking on event");
|
||||||
|
assert.strictEqual(calendar.$('.o_cw_popover .o_cw_popover_fields_secondary .list-group-item:last .o_field_date').text(), '01/07/2017', "should have correct start date");
|
||||||
calendar.destroy();
|
calendar.destroy();
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -2452,9 +2494,7 @@ QUnit.module('Views', {
|
|||||||
'date_start="start" '+
|
'date_start="start" '+
|
||||||
'date_stop="stop" '+
|
'date_stop="stop" '+
|
||||||
'mode="month" '+
|
'mode="month" '+
|
||||||
'form_view_id="42">'+
|
'form_view_id="42"/>',
|
||||||
'<field name="name"/>'+
|
|
||||||
'</calendar>',
|
|
||||||
archs: archs,
|
archs: archs,
|
||||||
viewOptions: {
|
viewOptions: {
|
||||||
initialDate: initialDate,
|
initialDate: initialDate,
|
||||||
@@ -2536,9 +2576,7 @@ QUnit.module('Views', {
|
|||||||
arch: '<calendar class="o_calendar_test" '+
|
arch: '<calendar class="o_calendar_test" '+
|
||||||
'date_start="start" '+
|
'date_start="start" '+
|
||||||
'date_stop="stop" '+
|
'date_stop="stop" '+
|
||||||
'mode="month"> '+
|
'mode="month"/>',
|
||||||
'<field name="name"/>'+
|
|
||||||
'</calendar>',
|
|
||||||
archs: archs,
|
archs: archs,
|
||||||
viewOptions: {
|
viewOptions: {
|
||||||
initialDate: initialDate,
|
initialDate: initialDate,
|
||||||
@@ -2593,9 +2631,7 @@ QUnit.module('Views', {
|
|||||||
arch: '<calendar class="o_calendar_test" '+
|
arch: '<calendar class="o_calendar_test" '+
|
||||||
'date_start="start" '+
|
'date_start="start" '+
|
||||||
'date_stop="stop" '+
|
'date_stop="stop" '+
|
||||||
'mode="week"> '+
|
'mode="week"/>',
|
||||||
'<field name="name"/>'+
|
|
||||||
'</calendar>',
|
|
||||||
archs: archs,
|
archs: archs,
|
||||||
viewOptions: {
|
viewOptions: {
|
||||||
initialDate: initialDate,
|
initialDate: initialDate,
|
||||||
@@ -2604,7 +2640,7 @@ QUnit.module('Views', {
|
|||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
assert.strictEqual(calendar.$('.fc-day-header:first').text(), "zz1. 11/12",
|
assert.strictEqual(calendar.$('.fc-day-header:first').text(), "zz1. 11",
|
||||||
'The day should be in the given locale specific format');
|
'The day should be in the given locale specific format');
|
||||||
|
|
||||||
moment.locale(initialLocale);
|
moment.locale(initialLocale);
|
||||||
@@ -2612,45 +2648,6 @@ QUnit.module('Views', {
|
|||||||
calendar.destroy();
|
calendar.destroy();
|
||||||
});
|
});
|
||||||
|
|
||||||
QUnit.test('calendar sidebar toggle', async function (assert) {
|
|
||||||
assert.expect(5);
|
|
||||||
|
|
||||||
var calendar = await createCalendarView({
|
|
||||||
View: CalendarView,
|
|
||||||
model: 'event',
|
|
||||||
data: this.data,
|
|
||||||
arch:
|
|
||||||
'<calendar date_start="start_date">'+
|
|
||||||
'<field name="name"/>'+
|
|
||||||
'</calendar>',
|
|
||||||
services: {
|
|
||||||
local_storage: AbstractStorageService.extend({storage: new RamStorage()}),
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
var fullWidth = calendar.call('local_storage', 'getItem', 'calendar_fullWidth');
|
|
||||||
assert.strictEqual(fullWidth, undefined,
|
|
||||||
"calendar_fullWidth should be undefined in local storage");
|
|
||||||
assert.containsNone(calendar, '.o_calendar_sidebar_container.o_sidebar_hidden',
|
|
||||||
"sidebar should be opened");
|
|
||||||
|
|
||||||
// click on close
|
|
||||||
await testUtils.dom.click(calendar.$('.o_calendar_sidebar_toggler'));
|
|
||||||
fullWidth = calendar.call('local_storage', 'getItem', 'calendar_fullWidth');
|
|
||||||
assert.strictEqual(fullWidth, true,
|
|
||||||
"calendar_fullWidth should be true in local storage");
|
|
||||||
assert.containsOnce(calendar, '.o_calendar_sidebar_container.o_sidebar_hidden',
|
|
||||||
"sidebar should be hidden");
|
|
||||||
|
|
||||||
// reload calendar view and check calendar view has still full width
|
|
||||||
calendar.reload();
|
|
||||||
await testUtils.nextTick();
|
|
||||||
assert.containsOnce(calendar, '.o_calendar_sidebar_container.o_sidebar_hidden',
|
|
||||||
"sidebar should be hidden");
|
|
||||||
|
|
||||||
calendar.destroy();
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -355,6 +355,7 @@
|
|||||||
|
|
||||||
<script type="text/javascript" src="/web/static/src/js/views/calendar/calendar_controller.js"></script>
|
<script type="text/javascript" src="/web/static/src/js/views/calendar/calendar_controller.js"></script>
|
||||||
<script type="text/javascript" src="/web/static/src/js/views/calendar/calendar_model.js"></script>
|
<script type="text/javascript" src="/web/static/src/js/views/calendar/calendar_model.js"></script>
|
||||||
|
<script type="text/javascript" src="/web/static/src/js/views/calendar/calendar_popover.js"></script>
|
||||||
<script type="text/javascript" src="/web/static/src/js/views/calendar/calendar_quick_create.js"></script>
|
<script type="text/javascript" src="/web/static/src/js/views/calendar/calendar_quick_create.js"></script>
|
||||||
<script type="text/javascript" src="/web/static/src/js/views/calendar/calendar_renderer.js"></script>
|
<script type="text/javascript" src="/web/static/src/js/views/calendar/calendar_renderer.js"></script>
|
||||||
<script type="text/javascript" src="/web/static/src/js/views/calendar/calendar_view.js"></script>
|
<script type="text/javascript" src="/web/static/src/js/views/calendar/calendar_view.js"></script>
|
||||||
|
|||||||
@@ -1168,8 +1168,6 @@ calendar view are:
|
|||||||
same color segment are allocated the same highlight color in the calendar,
|
same color segment are allocated the same highlight color in the calendar,
|
||||||
colors are allocated semi-randomly.
|
colors are allocated semi-randomly.
|
||||||
Displayed the display_name/avatar of the visible record in the sidebar
|
Displayed the display_name/avatar of the visible record in the sidebar
|
||||||
``readonly_form_view_id``
|
|
||||||
view to open in readonly mode
|
|
||||||
``form_view_id``
|
``form_view_id``
|
||||||
view to open when the user create or edit an event. Note that if this attribute
|
view to open when the user create or edit an event. Note that if this attribute
|
||||||
is not set, the calendar view will fall back to the id of the form view in the
|
is not set, the calendar view will fall back to the id of the form view in the
|
||||||
|
|||||||
@@ -13,13 +13,14 @@
|
|||||||
<rng:optional><rng:attribute name="date_stop" /></rng:optional>
|
<rng:optional><rng:attribute name="date_stop" /></rng:optional>
|
||||||
<rng:optional><rng:attribute name="date_delay" /></rng:optional>
|
<rng:optional><rng:attribute name="date_delay" /></rng:optional>
|
||||||
<rng:optional><rng:attribute name="all_day" /></rng:optional>
|
<rng:optional><rng:attribute name="all_day" /></rng:optional>
|
||||||
<rng:optional><rng:attribute name="readonly_form_view_id" /></rng:optional>
|
|
||||||
<rng:optional><rng:attribute name="form_view_id" /></rng:optional>
|
<rng:optional><rng:attribute name="form_view_id" /></rng:optional>
|
||||||
<rng:optional><rng:attribute name="event_limit" /></rng:optional>
|
<rng:optional><rng:attribute name="event_limit" /></rng:optional>
|
||||||
<rng:optional><rng:attribute name="quick_add" /></rng:optional>
|
<rng:optional><rng:attribute name="quick_add" /></rng:optional>
|
||||||
<rng:optional><rng:attribute name="color" /></rng:optional>
|
<rng:optional><rng:attribute name="color" /></rng:optional>
|
||||||
<rng:optional><rng:attribute name="event_open_popup" /></rng:optional>
|
<rng:optional><rng:attribute name="event_open_popup" /></rng:optional>
|
||||||
<rng:optional><rng:attribute name="js_class"/></rng:optional>
|
<rng:optional><rng:attribute name="js_class"/></rng:optional>
|
||||||
|
<rng:optional><rng:attribute name="hide_time"/></rng:optional>
|
||||||
|
<rng:optional><rng:attribute name="hide_date"/></rng:optional>
|
||||||
<rng:optional>
|
<rng:optional>
|
||||||
<rng:attribute name="mode">
|
<rng:attribute name="mode">
|
||||||
<rng:choice>
|
<rng:choice>
|
||||||
@@ -32,13 +33,6 @@
|
|||||||
<rng:zeroOrMore>
|
<rng:zeroOrMore>
|
||||||
<rng:ref name="field"/>
|
<rng:ref name="field"/>
|
||||||
</rng:zeroOrMore>
|
</rng:zeroOrMore>
|
||||||
<rng:optional>
|
|
||||||
<rng:element name="templates">
|
|
||||||
<rng:oneOrMore>
|
|
||||||
<rng:ref name="any"/>
|
|
||||||
</rng:oneOrMore>
|
|
||||||
</rng:element>
|
|
||||||
</rng:optional>
|
|
||||||
</rng:element>
|
</rng:element>
|
||||||
</rng:define>
|
</rng:define>
|
||||||
<rng:start>
|
<rng:start>
|
||||||
|
|||||||
Reference in New Issue
Block a user