diff options
| author | stephanchrst <stephanchrst@gmail.com> | 2022-05-10 21:51:50 +0700 |
|---|---|---|
| committer | stephanchrst <stephanchrst@gmail.com> | 2022-05-10 21:51:50 +0700 |
| commit | 3751379f1e9a4c215fb6eb898b4ccc67659b9ace (patch) | |
| tree | a44932296ef4a9b71d5f010906253d8c53727726 /addons/web/static/src/js/views/calendar/calendar_controller.js | |
| parent | 0a15094050bfde69a06d6eff798e9a8ddf2b8c21 (diff) | |
initial commit 2
Diffstat (limited to 'addons/web/static/src/js/views/calendar/calendar_controller.js')
| -rw-r--r-- | addons/web/static/src/js/views/calendar/calendar_controller.js | 477 |
1 files changed, 477 insertions, 0 deletions
diff --git a/addons/web/static/src/js/views/calendar/calendar_controller.js b/addons/web/static/src/js/views/calendar/calendar_controller.js new file mode 100644 index 00000000..0ab74b34 --- /dev/null +++ b/addons/web/static/src/js/views/calendar/calendar_controller.js @@ -0,0 +1,477 @@ +odoo.define('web.CalendarController', function (require) { +"use strict"; + +/** + * Calendar Controller + * + * This is the controller in the Model-Renderer-Controller architecture of the + * calendar view. Its role is to coordinate the data from the calendar model + * with the renderer, and with the outside world (such as a search view input) + */ + +var AbstractController = require('web.AbstractController'); +var core = require('web.core'); +var Dialog = require('web.Dialog'); +var dialogs = require('web.view_dialogs'); +var QuickCreate = require('web.CalendarQuickCreate'); + +var _t = core._t; +var QWeb = core.qweb; + +function dateToServer (date, fieldType) { + date = date.clone().locale('en'); + if (fieldType === "date") { + return date.local().format('YYYY-MM-DD'); + } + return date.utc().format('YYYY-MM-DD HH:mm:ss'); +} + +var CalendarController = AbstractController.extend({ + custom_events: _.extend({}, AbstractController.prototype.custom_events, { + changeDate: '_onChangeDate', + changeFilter: '_onChangeFilter', + deleteRecord: '_onDeleteRecord', + dropRecord: '_onDropRecord', + next: '_onNext', + openCreate: '_onOpenCreate', + openEvent: '_onOpenEvent', + prev: '_onPrev', + quickCreate: '_onQuickCreate', + updateRecord: '_onUpdateRecord', + viewUpdated: '_onViewUpdated', + }), + events: _.extend({}, AbstractController.prototype.events, { + 'click button.o_calendar_button_new': '_onButtonNew', + 'click button.o_calendar_button_prev': '_onButtonNavigation', + 'click button.o_calendar_button_today': '_onButtonNavigation', + 'click button.o_calendar_button_next': '_onButtonNavigation', + 'click button.o_calendar_button_day': '_onButtonScale', + 'click button.o_calendar_button_week': '_onButtonScale', + 'click button.o_calendar_button_month': '_onButtonScale', + 'click button.o_calendar_button_year': '_onButtonScale', + }), + /** + * @override + * @param {Widget} parent + * @param {AbstractModel} model + * @param {AbstractRenderer} renderer + * @param {Object} params + */ + init: function (parent, model, renderer, params) { + this._super.apply(this, arguments); + this.current_start = null; + this.displayName = params.displayName; + this.quickAddPop = params.quickAddPop; + this.disableQuickCreate = params.disableQuickCreate; + this.eventOpenPopup = params.eventOpenPopup; + this.showUnusualDays = params.showUnusualDays; + this.formViewId = params.formViewId; + this.readonlyFormViewId = params.readonlyFormViewId; + this.mapping = params.mapping; + this.context = params.context; + this.previousOpen = null; + // The quickCreating attribute ensures that we don't do several create + this.quickCreating = false; + this.scales = params.scales; + }, + + //-------------------------------------------------------------------------- + // Public + //-------------------------------------------------------------------------- + + /** + * Render the buttons according to the CalendarView.buttons template and + * add listeners on it. Set this.$buttons with the produced jQuery element + * + * @param {jQuery} [$node] a jQuery node where the rendered buttons + * should be inserted. $node may be undefined, in which case the Calendar + * inserts them into this.options.$buttons or into a div of its template + */ + renderButtons: function ($node) { + this.$buttons = $(QWeb.render('CalendarView.buttons', this._renderButtonsParameters())); + + this.$buttons.find('.o_calendar_button_' + this.mode).addClass('active'); + + if ($node) { + this.$buttons.appendTo($node); + } else { + this.$('.o_calendar_buttons').replaceWith(this.$buttons); + } + }, + + //-------------------------------------------------------------------------- + // Private + //-------------------------------------------------------------------------- + + /** + * Find a className in an array using the start of this class and + * return the last part of a string + * @private + * @param {string} startClassName start of string to find in the "array" + * @param {array|DOMTokenList} classList array of all class + * @return {string|undefined} + */ + _extractLastPartOfClassName(startClassName, classList) { + var result; + classList.forEach(function (value) { + if (value && value.indexOf(startClassName) === 0) { + result = value.substring(startClassName.length); + } + }); + return result; + }, + /** + * Move to the requested direction and reload the view + * + * @private + * @param {string} to either 'prev', 'next' or 'today' + * @returns {Promise} + */ + _move: function (to) { + this.model[to](); + return this.reload(); + }, + /** + * Parameter send to QWeb to render the template of Buttons + * + * @private + * @return {{}} + */ + _renderButtonsParameters() { + return { + scales: this.scales, + }; + }, + /** + * @override + * @private + */ + _update: function () { + var self = this; + if (!this.showUnusualDays) { + return this._super.apply(this, arguments); + } + return this._super.apply(this, arguments).then(function () { + self._rpc({ + model: self.modelName, + method: 'get_unusual_days', + args: [dateToServer(self.model.data.start_date, 'date'), dateToServer(self.model.data.end_date, 'date')], + context: self.context, + }).then(function (data) { + _.each(self.$el.find('td.fc-day'), function (td) { + var $td = $(td); + if (data[$td.data('date')]) { + $td.addClass('o_calendar_disabled'); + } + }); + }); + }); + }, + /** + * @private + * @param {Object} record + * @param {integer} record.id + * @returns {Promise} + */ + _updateRecord: function (record) { + var reload = this.reload.bind(this, {}); + return this.model.updateRecord(record).then(reload, reload); + }, + + //-------------------------------------------------------------------------- + // Handlers + //-------------------------------------------------------------------------- + + /** + * Handler when a user clicks on button to create event + * + * @private + */ + _onButtonNew() { + this.trigger_up('switch_view', {view_type: 'form'}); + }, + /** + * Handler when a user click on navigation button like prev, next, ... + * + * @private + * @param {Event|jQueryEvent} jsEvent + */ + _onButtonNavigation(jsEvent) { + const action = this._extractLastPartOfClassName('o_calendar_button_', jsEvent.currentTarget.classList); + if (action) { + this._move(action); + } + }, + /** + * Handler when a user click on scale button like day, month, ... + * + * @private + * @param {Event|jQueryEvent} jsEvent + */ + _onButtonScale(jsEvent) { + const scale = this._extractLastPartOfClassName('o_calendar_button_', jsEvent.currentTarget.classList); + if (scale) { + this.model.setScale(scale); + this.reload(); + } + }, + + /** + * @private + * @param {OdooEvent} event + */ + _onChangeDate: function (event) { + var modelData = this.model.get(); + if (modelData.target_date.format('YYYY-MM-DD') === event.data.date.format('YYYY-MM-DD')) { + // When clicking on same date, toggle between the two views + switch (modelData.scale) { + case 'month': this.model.setScale('week'); break; + case 'week': this.model.setScale('day'); break; + case 'day': this.model.setScale('month'); break; + } + } else if (modelData.target_date.week() === event.data.date.week()) { + // When clicking on a date in the same week, switch to day view + this.model.setScale('day'); + } else { + // When clicking on a random day of a random other week, switch to week view + this.model.setScale('week'); + } + this.model.setDate(event.data.date); + this.reload(); + }, + /** + * @private + * @param {OdooEvent} event + */ + _onChangeFilter: function (event) { + if (this.model.changeFilter(event.data) && !event.data.no_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 + * @param {OdooEvent} event + */ + _onDropRecord: function (event) { + this._updateRecord(_.extend({}, event.data, { + 'drop': true, + })); + }, + /** + * @private + * @param {OdooEvent} event + */ + _onNext: function (event) { + event.stopPropagation(); + this._move('next'); + }, + /** + * @private + * @param {OdooEvent} event + */ + _onOpenCreate: function (event) { + var self = this; + if (["year", "month"].includes(this.model.get().scale)) { + event.data.allDay = true; + } + var data = this.model.calendarEventToRecord(event.data); + + var context = _.extend({}, this.context, event.options && event.options.context); + // context default has more priority in default_get so if data.name is false then it may + // lead to error/warning while saving record in form view as name field can be required + if (data.name) { + context.default_name = data.name; + } + context['default_' + this.mapping.date_start] = data[this.mapping.date_start] || null; + if (this.mapping.date_stop) { + context['default_' + this.mapping.date_stop] = data[this.mapping.date_stop] || null; + } + if (this.mapping.date_delay) { + context['default_' + this.mapping.date_delay] = data[this.mapping.date_delay] || null; + } + if (this.mapping.all_day) { + context['default_' + this.mapping.all_day] = data[this.mapping.all_day] || null; + } + + for (var k in context) { + if (context[k] && context[k]._isAMomentObject) { + context[k] = dateToServer(context[k]); + } + } + + var options = _.extend({}, this.options, event.options, { + context: context, + title: _.str.sprintf(_t('Create: %s'), (this.displayName || this.renderer.arch.attrs.string)) + }); + + if (this.quick != null) { + this.quick.destroy(); + this.quick = null; + } + + if (!options.disableQuickCreate && !event.data.disableQuickCreate && this.quickAddPop) { + this.quick = new QuickCreate(this, true, options, data, event.data); + this.quick.open(); + this.quick.opened(function () { + self.quick.focus(); + }); + return; + } + + var title = _t("Create"); + if (this.renderer.arch.attrs.string) { + title += ': ' + this.renderer.arch.attrs.string; + } + if (this.eventOpenPopup) { + if (this.previousOpen) { this.previousOpen.close(); } + this.previousOpen = new dialogs.FormViewDialog(self, { + res_model: this.modelName, + context: context, + title: title, + view_id: this.formViewId || false, + disable_multiple_selection: true, + on_saved: function () { + if (event.data.on_save) { + event.data.on_save(); + } + self.reload(); + }, + }); + this.previousOpen.open(); + } else { + this.do_action({ + type: 'ir.actions.act_window', + res_model: this.modelName, + views: [[this.formViewId || false, 'form']], + target: 'current', + context: context, + }); + } + }, + /** + * @private + * @param {OdooEvent} event + */ + _onOpenEvent: function (event) { + var self = this; + var id = event.data._id; + id = id && parseInt(id).toString() === id ? parseInt(id) : id; + + if (!this.eventOpenPopup) { + this._rpc({ + model: self.modelName, + method: 'get_formview_id', + //The event can be called by a view that can have another context than the default one. + args: [[id]], + context: event.context || self.context, + }).then(function (viewId) { + self.do_action({ + type:'ir.actions.act_window', + res_id: id, + res_model: self.modelName, + views: [[viewId || false, 'form']], + target: 'current', + context: event.context || self.context, + }); + }); + return; + } + + var options = { + res_model: self.modelName, + res_id: id || null, + context: event.context || self.context, + title: _t("Open: ") + _.escape(event.data.title), + on_saved: function () { + if (event.data.on_save) { + event.data.on_save(); + } + self.reload(); + }, + }; + if (this.formViewId) { + options.view_id = parseInt(this.formViewId); + } + new dialogs.FormViewDialog(this, options).open(); + }, + /** + * @private + * @param {OdooEvent} event + */ + _onPrev: function () { + event.stopPropagation(); + this._move('prev'); + }, + + /** + * Handles saving data coming from quick create box + * + * @private + * @param {OdooEvent} event + */ + _onQuickCreate: function (event) { + var self = this; + if (this.quickCreating) { + return; + } + this.quickCreating = true; + this.model.createRecord(event) + .then(function () { + self.quick.destroy(); + self.quick = null; + self.reload(); + self.quickCreating = false; + }) + .guardedCatch(function (result) { + var errorEvent = result.event; + // This will occurs if there are some more fields required + // Preventdefaulting the error event will prevent the traceback window + errorEvent.preventDefault(); + event.data.options.disableQuickCreate = true; + event.data.data.on_save = self.quick.destroy.bind(self.quick); + self._onOpenCreate(event.data); + self.quickCreating = false; + }); + }, + /** + * @private + * @param {OdooEvent} event + */ + _onUpdateRecord: function (event) { + this._updateRecord(event.data); + }, + /** + * The internal state of the calendar (mode, period displayed) has changed, + * so update the control panel buttons and breadcrumbs accordingly. + * + * @private + * @param {OdooEvent} event + */ + _onViewUpdated: function (event) { + this.mode = event.data.mode; + if (this.$buttons) { + this.$buttons.find('.active').removeClass('active'); + this.$buttons.find('.o_calendar_button_' + this.mode).addClass('active'); + } + const title = `${this.displayName} (${event.data.title})`; + return this.updateControlPanel({ title }); + }, +}); + +return CalendarController; + +}); |
