flectra.define('board.dashboard', function (require) { "use strict"; var Context = require('web.Context'); var core = require('web.core'); var dataManager = require('web.data_manager'); var Dialog = require('web.Dialog'); var Domain = require('web.Domain'); var FormController = require('web.FormController'); var FormRenderer = require('web.FormRenderer'); var FormView = require('web.FormView'); var viewRegistry = require('web.view_registry'); var _t = core._t; var QWeb = core.qweb; FormView.include({ /** * @override */ init: function (viewInfo) { this._super.apply(this, arguments); this.controllerParams.customViewID = viewInfo.custom_view_id; }, }); FormController.include({ custom_events: _.extend({}, FormController.prototype.custom_events, { change_layout: '_onChangeLayout', enable_dashboard: '_onEnableDashboard', save_dashboard: '_saveDashboard', switch_view: '_onSwitchView', }), init: function (parent, model, renderer, params) { this._super.apply(this, arguments); this.customViewID = params.customViewID; }, //-------------------------------------------------------------------------- // Public //-------------------------------------------------------------------------- /** * @override */ getTitle: function () { if (this.inDashboard) { return _t("My Dashboard"); } return this._super.apply(this, arguments); }, //-------------------------------------------------------------------------- // Private //-------------------------------------------------------------------------- /** * Actually save a dashboard * * @returns {Deferred} */ _saveDashboard: function () { var board = this.renderer.getBoard(); var arch = QWeb.render('DashBoard.xml', _.extend({}, board)); return this._rpc({ route: '/web/view/edit_custom', params: { custom_id: this.customViewID, arch: arch, } }).then(dataManager.invalidate.bind(dataManager)); }, //-------------------------------------------------------------------------- // Handlers //-------------------------------------------------------------------------- /** * @private * @param {FlectraEvent} event */ _onChangeLayout: function (event) { var self = this; var dialog = new Dialog(this, { title: _t("Edit Layout"), $content: QWeb.render('DashBoard.layouts', _.clone(event.data)) }); dialog.opened().then(function () { dialog.$('li').click(function () { var layout = $(this).attr('data-layout'); self.renderer.changeLayout(layout); self._saveDashboard(); dialog.close(); }); }); dialog.open(); }, /** * @private */ _onEnableDashboard: function () { this.inDashboard = true; }, /** * We need to intercept switch_view event coming from sub views, because * there is no view manager doing the job. Also, we don't actually want to * switch view in dashboard, we want to do a do_action (which will open the * record in a different breadcrumb) * * @private * @param {FlectraEvent} event */ _onSwitchView: function (event) { event.stopPropagation(); this.do_action({ type: 'ir.actions.act_window', res_model: event.data.model, views: [[false, 'form']], res_id: event.data.res_id, }); }, }); FormRenderer.include({ events: _.extend({}, FormRenderer.prototype.events, { 'click .oe_dashboard_column .oe_fold': '_onFoldClick', 'click .oe_dashboard_link_change_layout': '_onChangeLayout', 'click .oe_dashboard_column .oe_close': '_onCloseAction', }), /** * @override */ init: function (parent, state, params) { this._super.apply(this, arguments); this.noContentHelp = params.noContentHelp; this.actionsDescr = {}; this._boardSubcontrollers = []; // for board: controllers of subviews }, /** * Call `on_attach_callback` for each subview * * @override */ on_attach_callback: function () { _.each(this._boardSubcontrollers, function (controller) { if ('on_attach_callback' in controller) { controller.on_attach_callback(); } }); }, /** * Call `on_detach_callback` for each subview * * @override */ on_detach_callback: function () { _.each(this._boardSubcontrollers, function (controller) { if ('on_detach_callback' in controller) { controller.on_detach_callback(); } }); }, //-------------------------------------------------------------------------- // Public //-------------------------------------------------------------------------- /** * @param {string} layout */ changeLayout: function (layout) { var $dashboard = this.$('.oe_dashboard'); var current_layout = $dashboard.attr('data-layout'); if (current_layout !== layout) { var clayout = current_layout.split('-').length, nlayout = layout.split('-').length, column_diff = clayout - nlayout; if (column_diff > 0) { var $last_column = $(); $dashboard.find('.oe_dashboard_column').each(function (k, v) { if (k >= nlayout) { $(v).find('.oe_action').appendTo($last_column); } else { $last_column = $(v); } }); } $dashboard.toggleClass('oe_dashboard_layout_' + current_layout + ' oe_dashboard_layout_' + layout); $dashboard.attr('data-layout', layout); } }, /** * Returns a representation of the current dashboard * * @returns {Object} */ getBoard: function () { var self = this; var board = { form_title : this.arch.attrs.string, style : this.$('.oe_dashboard').attr('data-layout'), columns : [], }; this.$('.oe_dashboard_column').each(function () { var actions = []; $(this).find('.oe_action').each(function () { var actionID = $(this).attr('data-id'); var newAttrs = _.clone(self.actionsDescr[actionID]); /* prepare attributes as they should be saved */ if (newAttrs.modifiers) { newAttrs.modifiers = JSON.stringify(newAttrs.modifiers); } actions.push(newAttrs); }); board.columns.push(actions); }); return board; }, //-------------------------------------------------------------------------- // Private //-------------------------------------------------------------------------- /** * @private * @param {Object} params * @param {jQueryElement} params.$node * @param {integer} params.actionID * @param {Object} params.context * @param {any[]} params.domain * @param {string} params.viewType * @returns {Deferred} */ _createController: function (params) { var self = this; var context = params.context.eval(); return this._rpc({ route: '/web/action/load', params: {action_id: params.actionID} }) .then(function (action) { if (!action) { // the action does not exist anymore return $.when(); } var view = _.find(action.views, function (descr) { return descr[1] === params.viewType; }); return self.loadViews(action.res_model, params.context, [view]) .then(function (viewsInfo) { var viewInfo = viewsInfo[params.viewType]; var View = viewRegistry.get(params.viewType); var view = new View(viewInfo, { action: action, context: context, domain: params.domain, groupBy: context.group_by, modelName: action.res_model, hasSelectors: false, }); return view.getController(self).then(function (controller) { self._boardSubcontrollers.push(controller); return controller.appendTo(params.$node); }); }); }); }, /** * @private * @param {Object} node * @returns {jQueryElement} */ _renderTagBoard: function (node) { var self = this; // we add the o_dashboard class to the renderer's $el. This means that // this function has a side effect. This is ok because we assume that // once we have a '' tag, we are in a special dashboard mode. this.$el.addClass('o_dashboard'); this.trigger_up('enable_dashboard'); var hasAction = _.detect(node.children, function (column) { return _.detect(column.children,function (element){ return element.tag === "action"? element: false; }); }); if (!hasAction) { return $('
') .append($('
').html(this.noContentHelp || " ")); } // We should start with three columns available node = $.extend(true, {}, node); // no idea why master works without this, but whatever if (!('layout' in node.attrs)) { node.attrs.layout = node.attrs.style; } for (var i = node.children.length; i < 3; i++) { node.children.push({ tag: 'column', attrs: {}, children: [] }); } // register actions, alongside a generated unique ID _.each(node.children, function (column, column_index) { _.each(column.children, function (action, action_index) { action.attrs.id = 'action_' + column_index + '_' + action_index; self.actionsDescr[action.attrs.id] = action.attrs; }); }); var $html = $('
').append($(QWeb.render('DashBoard', {node: node}))); // render each view _.each(this.actionsDescr, function (action) { self.defs.push(self._createController({ $node: $html.find('.oe_action[data-id=' + action.id + '] .oe_content'), actionID: _.str.toNumber(action.name), context: new Context(action.context), domain: Domain.prototype.stringToArray(action.domain, {}), viewType: action.view_mode, })); }); $html.find('.oe_dashboard_column').sortable({ connectWith: '.oe_dashboard_column', handle: '.oe_header', scroll: false }).bind('sortstop', function () { self.trigger_up('save_dashboard'); }); return $html; }, //-------------------------------------------------------------------------- // Handlers //-------------------------------------------------------------------------- /** * @private */ _onChangeLayout: function () { var currentLayout = this.$('.oe_dashboard').attr('data-layout'); this.trigger_up('change_layout', {currentLayout: currentLayout}); }, /** * @private * @param {MouseEvent} event */ _onCloseAction: function (event) { var self = this; var $container = $(event.currentTarget).parents('.oe_action:first'); Dialog.confirm(this, (_t("Are you sure you want to remove this item?")), { confirm_callback: function () { $container.remove(); self.trigger_up('save_dashboard'); }, }); }, /** * @private * @param {MouseEvent} event */ _onFoldClick: function (event) { var $e = $(event.currentTarget); var $action = $e.closest('.oe_action'); var id = $action.data('id'); var actionAttrs = this.actionsDescr[id]; if ($e.is('.oe_minimize')) { actionAttrs.fold = '1'; } else { delete(actionAttrs.fold); } $e.toggleClass('oe_minimize oe_maximize'); $action.find('.oe_content').toggle(); this.trigger_up('save_dashboard'); }, }); });