diff options
Diffstat (limited to 'addons/web/static/src/js/views/abstract_controller.js')
| -rw-r--r-- | addons/web/static/src/js/views/abstract_controller.js | 170 |
1 files changed, 137 insertions, 33 deletions
diff --git a/addons/web/static/src/js/views/abstract_controller.js b/addons/web/static/src/js/views/abstract_controller.js index 3bdf8ab08ca..150b4803a7a 100644 --- a/addons/web/static/src/js/views/abstract_controller.js +++ b/addons/web/static/src/js/views/abstract_controller.js @@ -12,12 +12,16 @@ odoo.define('web.AbstractController', function (require) { * reading localstorage, ...) has to go through the controller. */ +var ControlPanelMixin = require('web.ControlPanelMixin'); +var core = require('web.core'); var Widget = require('web.Widget'); +var QWeb = core.qweb; -var AbstractController = Widget.extend({ +var AbstractController = Widget.extend(ControlPanelMixin, { custom_events: { open_record: '_onOpenRecord', + switch_view: '_onSwitchView', }, events: { 'click a[type="action"]': '_onActionClicked', @@ -30,8 +34,15 @@ var AbstractController = Widget.extend({ * @param {AbstractRenderer} renderer * @param {object} params * @param {string} params.modelName + * @param {string} [params.controllerID] an id to ease the communication + * with upstream components * @param {any} [params.handle] a handle that will be given to the model (some id) * @param {any} params.initialState the initialState + * @param {boolean} params.isMultiRecord + * @param {Object[]} params.actionViews + * @param {string} params.viewType + * @param {boolean} params.withControlPanel set to false to hide the + * ControlPanel */ init: function (parent, model, renderer, params) { this._super.apply(this, arguments); @@ -40,7 +51,23 @@ var AbstractController = Widget.extend({ this.modelName = params.modelName; this.handle = params.handle; this.activeActions = params.activeActions; + this.controllerID = params.controllerID; this.initialState = params.initialState; + + // those arguments are temporary, they won't be necessary as soon as the + // ControlPanel will be handled by the View + this.displayName = params.displayName; + this.isMultiRecord = params.isMultiRecord; + this.searchable = params.searchable; + this.searchView = params.searchView; + this.searchViewHidden = params.searchViewHidden; + this.actionViews = params.actionViews; + this.viewType = params.viewType; + this.withControlPanel = params.withControlPanel !== false; + // override this.need_control_panel so that the ActionManager doesn't + // update the control panel when it isn't visible (this is a temporary + // hack that can be removed as soon as the CP'll be handled by the view) + this.need_control_panel = this.withControlPanel; }, /** * Simply renders and updates the url. @@ -48,10 +75,19 @@ var AbstractController = Widget.extend({ * @returns {Deferred} */ start: function () { + var self = this; + + this.$el.addClass('o_view_controller'); + + // render the ControlPanel elements (buttons, pager, sidebar...) + this.controlPanelElements = this._renderControlPanelElements(); + return $.when( this._super.apply(this, arguments), this.renderer.appendTo(this.$el) - ).then(this._update.bind(this, this.initialState)); + ).then(function () { + self._update(self.initialState); + }); }, /** * @override @@ -60,6 +96,9 @@ var AbstractController = Widget.extend({ if (this.$buttons) { this.$buttons.off(); } + if (this.controlPanelElements && this.controlPanelElements.$switch_buttons) { + this.controlPanelElements.$switch_buttons.off(); + } return this._super.apply(this, arguments); }, @@ -70,7 +109,7 @@ var AbstractController = Widget.extend({ /** * Discards the changes made on the record associated to the given ID, or * all changes made by the current controller if no recordID is given. For - * example, when the user open the 'home' screen, the view manager will call + * example, when the user opens the 'home' screen, the action manager calls * this method on the active view to make sure it is ok to open the home * screen (and lose all current state). * @@ -96,23 +135,15 @@ var AbstractController = Widget.extend({ return {}; }, /** - * @see setScrollTop - * @returns {number} - */ - getScrollTop: function () { - return this.scrollTop; - }, - /** * Returns a title that may be displayed in the breadcrumb area. For * example, the name of the record. * - * Note: this seems wrong right now, it should not be implemented, we have - * no guarantee that there is a display_name variable in a controller. + * note: this will be moved to AbstractAction * * @returns {string} */ getTitle: function () { - return this.display_name; + return this.displayName; }, /** * The use of this method is discouraged. It is still snakecased, because @@ -136,12 +167,9 @@ var AbstractController = Widget.extend({ return this.update(params || {}); }, /** - * Most likely called by the view manager, this method is responsible for - * adding buttons in the control panel (buttons such as save/discard/...) - * - * Note that there is no guarantee that this method will be called. The - * controller is supposed to work even without a view manager, for example - * in the frontend (odoo frontend = public website) + * Renders the buttons to append, in most cases, to the control panel (in + * the bottom left corner). When the view is rendered in a dialog, those + * buttons might be moved to the dialog's footer. * * @param {jQuery Node} $node */ @@ -153,7 +181,7 @@ var AbstractController = Widget.extend({ * controller can actually render whatever he wants in the pager zone. If * your view does not want a pager, just let this method empty. * - * @param {Query Node} $node + * @param {jQuery Node} $node */ renderPager: function ($node) { }, @@ -161,21 +189,11 @@ var AbstractController = Widget.extend({ * Same as renderPager, but for the 'sidebar' zone (the zone with the menu * dropdown in the control panel next to the buttons) * - * @param {Query Node} $node + * @param {jQuery Node} $node */ renderSidebar: function ($node) { }, /** - * Not sure about this one, it probably needs to be reworked, maybe merged - * in get/set local state methods. - * - * @see getScrollTop - * @param {number} scrollTop - */ - setScrollTop: function (scrollTop) { - this.scrollTop = scrollTop; - }, - /** * This is the main entry point for the controller. Changes from the search * view arrive in this method, and internal changes can sometimes also call * this method. It is basically the way everything notifies the controller @@ -219,7 +237,68 @@ var AbstractController = Widget.extend({ * world */ _pushState: function (state) { - this.trigger_up('push_state', state || {}); + this.trigger_up('push_state', { + controllerID: this.controllerID, + state: state || {}, + }); + }, + /** + * Renders the control elements (buttons, pager and sidebar) of the current + * view. + * + * @private + * @returns {Object} an object containing the control panel jQuery elements + */ + _renderControlPanelElements: function () { + var elements = {}; + + if (this.withControlPanel) { + elements = { + $buttons: $('<div>'), + $sidebar: $('<div>'), + $pager: $('<div>'), + }; + + this.renderButtons(elements.$buttons); + this.renderSidebar(elements.$sidebar); + this.renderPager(elements.$pager); + // remove the unnecessary outer div + elements = _.mapObject(elements, function($node) { + return $node && $node.contents(); + }); + elements.$switch_buttons = this._renderSwitchButtons(); + } + + return elements; + }, + /** + * Renders the switch buttons and binds listeners on them. + * + * @private + * @returns {jQuery} + */ + _renderSwitchButtons: function () { + var self = this; + var views = _.filter(this.actionViews, {multiRecord: this.isMultiRecord}); + + if (views.length <= 1) { + return $(); + } + + var $switchButtons = $(QWeb.render('ControlPanel.SwitchButtons', { + views: views, + })); + // create bootstrap tooltips + _.each(views, function (view) { + $switchButtons.filter('.o_cp_switch_' + view.type).tooltip(); + }); + // add onclick event listener + $switchButtons.filter('button').click(_.debounce(function (event) { + var viewType = $(event.target).data('view-type'); + self.trigger_up('switch_view', {view_type: viewType}); + }, 200, true)); + + return $switchButtons; }, /** * This method is called after each update or when the start method is @@ -235,6 +314,22 @@ var AbstractController = Widget.extend({ * @returns {Deferred} */ _update: function (state) { + // AAB: update the control panel -> this will be moved elsewhere at some point + var cpContent = _.extend({}, this.controlPanelElements); + if (this.searchView) { + _.extend(cpContent, { + $searchview: this.searchView.$el, + $searchview_buttons: this.searchView.$buttons.contents(), + }); + } + this.update_control_panel({ + active_view_selector: '.o_cp_switch_' + this.viewType, + cp_content: cpContent, + hidden: !this.withControlPanel, + searchview: this.searchView, + search_view_hidden: !this.searchable || this.searchviewHidden, + }); + this._pushState(); return $.when(); }, @@ -249,7 +344,7 @@ var AbstractController = Widget.extend({ * * Note: this method seems wrong, it relies on the model being a basic model, * to get the res_id. It should receive the res_id in the event data - * @todo move this to basic controller? or view manager + * @todo move this to basic controller? * * @private * @param {OdooEvent} event @@ -278,6 +373,15 @@ var AbstractController = Widget.extend({ event.preventDefault(); this.do_action(event.target.name); }, + /** + * Intercepts the 'switch_view' event to add the controllerID into the data, + * and lets the event bubble up. + * + * @param {OdooEvent} event + */ + _onSwitchView: function (event) { + event.data.controllerID = this.controllerID; + }, }); |
