diff options
Diffstat (limited to 'addons/web/static/src')
11 files changed, 137 insertions, 116 deletions
diff --git a/addons/web/static/src/js/views/abstract_controller.js b/addons/web/static/src/js/views/abstract_controller.js index b84f6ec1951..3bdf8ab08ca 100644 --- a/addons/web/static/src/js/views/abstract_controller.js +++ b/addons/web/static/src/js/views/abstract_controller.js @@ -32,7 +32,6 @@ var AbstractController = Widget.extend({ * @param {string} params.modelName * @param {any} [params.handle] a handle that will be given to the model (some id) * @param {any} params.initialState the initialState - * @param {string} [params.noContentHelp] */ init: function (parent, model, renderer, params) { this._super.apply(this, arguments); @@ -42,7 +41,6 @@ var AbstractController = Widget.extend({ this.handle = params.handle; this.activeActions = params.activeActions; this.initialState = params.initialState; - this.noContentHelp = params.noContentHelp; }, /** * Simply renders and updates the url. @@ -224,31 +222,6 @@ var AbstractController = Widget.extend({ this.trigger_up('push_state', state || {}); }, /** - * Hide or show the nocontent helper. For this, it also remove the renderer - * from the dom, and reattach it when necessary. - * - * This method is a helper for controllers that want to display a help - * message when no content is available. It is suggested to override - * _update to call this method. - * - * @private - * @param {boolean} hasNoContent - */ - _toggleNoContentHelper: function (hasNoContent) { - if (hasNoContent && this.noContentHelp) { - this.renderer.$el.detach(); - var $msg = $('<div>') - .addClass('oe_view_nocontent') - .html(this.noContentHelp); - this.$el.html($msg); - } else { - if (!document.contains(this.renderer.el)) { - this.$('div.oe_view_nocontent').remove(); - this.$el.append(this.renderer.$el); - } - } - }, - /** * This method is called after each update or when the start method is * completed. * diff --git a/addons/web/static/src/js/views/abstract_renderer.js b/addons/web/static/src/js/views/abstract_renderer.js index 7d10f05eab8..d7eb5002f2d 100644 --- a/addons/web/static/src/js/views/abstract_renderer.js +++ b/addons/web/static/src/js/views/abstract_renderer.js @@ -15,11 +15,13 @@ return Widget.extend({ * @param {Widget} parent * @param {any} state * @param {Object} params + * @param {string} [params.noContentHelp] */ init: function (parent, state, params) { this._super(parent); this.state = state; this.arch = params.arch; + this.noContentHelp = params.noContentHelp; }, /** * The rendering can be asynchronous (but it is not encouraged). The start diff --git a/addons/web/static/src/js/views/abstract_view.js b/addons/web/static/src/js/views/abstract_view.js index e14e064ee33..74e1e1fce18 100644 --- a/addons/web/static/src/js/views/abstract_view.js +++ b/addons/web/static/src/js/views/abstract_view.js @@ -77,6 +77,7 @@ var AbstractView = Class.extend({ init: function (viewInfo, params) { this.rendererParams = { arch: viewInfo.arch, + noContentHelp: params.action && params.action.help, }; this.controllerParams = { @@ -87,7 +88,6 @@ var AbstractView = Class.extend({ delete: viewInfo.arch.attrs.delete ? JSON.parse(viewInfo.arch.attrs.delete) : true, duplicate: viewInfo.arch.attrs.duplicate ? JSON.parse(viewInfo.arch.attrs.duplicate) : true, }, - noContentHelp: params.action && params.action.help, }; this.loadParams = { diff --git a/addons/web/static/src/js/views/basic/basic_controller.js b/addons/web/static/src/js/views/basic/basic_controller.js index cc72816a85d..54c8ccfbf51 100644 --- a/addons/web/static/src/js/views/basic/basic_controller.js +++ b/addons/web/static/src/js/views/basic/basic_controller.js @@ -362,17 +362,6 @@ var BasicController = AbstractController.extend(FieldManagerMixin, { }; }, /** - * Used by list and kanban views to determine whether or not to display - * the no content helper (if there is no data in the state to display) - * - * @private - * @param {Object} state - * @returns {boolean} - */ - _hasContent: function (state) { - return state.count !== 0; - }, - /** * Helper function to display a warning that some fields have an invalid * value. This is used when a save operation cannot be completed. * diff --git a/addons/web/static/src/js/views/basic/basic_renderer.js b/addons/web/static/src/js/views/basic/basic_renderer.js index 8bbf9ae45a4..e040a5fa7f0 100644 --- a/addons/web/static/src/js/views/basic/basic_renderer.js +++ b/addons/web/static/src/js/views/basic/basic_renderer.js @@ -318,6 +318,16 @@ var BasicRenderer = AbstractRenderer.extend({ return _.findWhere(this.allModifiersData, {node: node}); }, /** + * Used by list and kanban renderers to determine whether or not to display + * the no content helper (if there is no data in the state to display) + * + * @private + * @returns {boolean} + */ + _hasContent: function () { + return this.state.count !== 0; + }, + /** * Registers or updates the modifiers data associated to the given node. * This method is quiet complex as it handles all the needs of the basic * renderers: @@ -487,6 +497,20 @@ var BasicRenderer = AbstractRenderer.extend({ return widget; }, /** + * Renders the nocontent helper. + * + * This method is a helper for renderers that want to display a help + * message when no content is available. + * + * @private + */ + _renderNoContentHelper: function () { + var $msg = $('<div>') + .addClass('oe_view_nocontent') + .html(this.noContentHelp); + this.$el.html($msg); + }, + /** * Actual rendering. Supposed to be overridden by concrete renderers. * The basic responsabilities of _renderView are: * - use the xml arch of the view to render a jQuery representation diff --git a/addons/web/static/src/js/views/kanban/kanban_controller.js b/addons/web/static/src/js/views/kanban/kanban_controller.js index 2592e3d96ec..2cf6a94285e 100644 --- a/addons/web/static/src/js/views/kanban/kanban_controller.js +++ b/addons/web/static/src/js/views/kanban/kanban_controller.js @@ -81,19 +81,6 @@ var KanbanController = BasicController.extend({ return this.renderer.updateRecord(this.model.get(id)); }, /** - * The nocontent helper should be displayed in kanban: - * - ungrouped: if there is no records - * - grouped: if there is no groups and no column quick create - * - * @override - * @private - */ - _hasContent: function (state) { - return this._super.apply(this, arguments) || - this.createColumnEnabled || - (state.groupedBy.length && state.data.length); - }, - /** * The column quick create should be displayed in kanban iff grouped by an * m2o field and group_create action enabled. * @@ -138,17 +125,6 @@ var KanbanController = BasicController.extend({ .toggleClass('btn-default', createMuted); } }, - /** - * @override - * @param {Object} state - * @returns {Deferred} - */ - _update: function (state) { - var hasNoContent = !this._hasContent(state); - this.$el.toggleClass('o_kanban_nocontent', hasNoContent); - this._toggleNoContentHelper(hasNoContent); - return this._super.apply(this, arguments); - }, //-------------------------------------------------------------------------- // Handlers diff --git a/addons/web/static/src/js/views/kanban/kanban_renderer.js b/addons/web/static/src/js/views/kanban/kanban_renderer.js index ea2f0270017..0bbc7aa2698 100644 --- a/addons/web/static/src/js/views/kanban/kanban_renderer.js +++ b/addons/web/static/src/js/views/kanban/kanban_renderer.js @@ -100,6 +100,8 @@ var KanbanRenderer = BasicRenderer.extend({ viewType: 'kanban', }); this.columnOptions = _.extend({}, params.column_options, { qweb: this.qweb }); + + this._setState(state); }, //-------------------------------------------------------------------------- @@ -167,12 +169,32 @@ var KanbanRenderer = BasicRenderer.extend({ record.update(recordState); } }, + /** + * @override + */ + updateState: function (state) { + this._setState(state); + return this._super.apply(this, arguments); + }, //-------------------------------------------------------------------------- // Private //-------------------------------------------------------------------------- /** + * The nocontent helper should be displayed in kanban: + * - ungrouped: if there is no records + * - grouped: if there is no groups and no column quick create + * + * @override + * @private + */ + _hasContent: function () { + return this._super.apply(this, arguments) || + this.createColumnEnabled || + (this.state.groupedBy.length && this.state.data.length); + }, + /** * Renders empty invisible divs in a document fragment. * * @private @@ -193,28 +215,6 @@ var KanbanRenderer = BasicRenderer.extend({ */ _renderGrouped: function (fragment) { var self = this; - var groupByFieldAttrs = this.state.fields[this.state.groupedBy[0]]; - var groupByFieldInfo = this.state.fieldsInfo.kanban[this.state.groupedBy[0]]; - // Deactivate the drag'n'drop if the groupedBy field: - // - is a date or datetime since we group by month or - // - is readonly - var draggable = true; - if (groupByFieldAttrs) { - if (groupByFieldAttrs.type === "date" || groupByFieldAttrs.type === "datetime") { - draggable = false; - } else if (groupByFieldAttrs.readonly !== undefined) { - draggable = !(groupByFieldAttrs.readonly); - } - } - var groupedByM2O = groupByFieldAttrs && (groupByFieldAttrs.type === 'many2one'); - var grouped_by_field = groupedByM2O && groupByFieldAttrs.relation; - var groupByTooltip = groupByFieldInfo && groupByFieldInfo.options.group_by_tooltip; - this.columnOptions = _.extend(this.columnOptions, { - draggable: draggable, - group_by_tooltip: groupByTooltip, - grouped_by_m2o: groupedByM2O, - relation: grouped_by_field, - }); // Render columns _.each(this.state.data, function (group) { @@ -228,7 +228,7 @@ var KanbanRenderer = BasicRenderer.extend({ } }); - if (groupedByM2O) { + if (this.groupedByM2O) { // Enable column sorting this.$el.sortable({ axis: 'x', @@ -249,7 +249,7 @@ var KanbanRenderer = BasicRenderer.extend({ }); // Enable column quickcreate - if (this.columnOptions.group_creatable) { + if (this.createColumnEnabled) { this.quickCreate = new ColumnQuickCreate(this); this.quickCreate.appendTo(fragment); } @@ -280,20 +280,62 @@ var KanbanRenderer = BasicRenderer.extend({ _renderView: function () { var oldWidgets = this.widgets; this.widgets = []; - var isGrouped = !!this.state.groupedBy.length; - this.$el.toggleClass('o_kanban_grouped', isGrouped); - this.$el.toggleClass('o_kanban_ungrouped', !isGrouped); this.$el.empty(); - var fragment = document.createDocumentFragment(); - if (isGrouped) { - this._renderGrouped(fragment); + var displayNoContentHelper = !this._hasContent() && !!this.noContentHelp; + this.$el.toggleClass('o_kanban_nocontent', displayNoContentHelper); + if (displayNoContentHelper) { + // display the no content helper if there is no data to display + this._renderNoContentHelper(); } else { - this._renderUngrouped(fragment); + var isGrouped = !!this.state.groupedBy.length; + this.$el.toggleClass('o_kanban_grouped', isGrouped); + this.$el.toggleClass('o_kanban_ungrouped', !isGrouped); + var fragment = document.createDocumentFragment(); + // render the kanban view + if (isGrouped) { + this._renderGrouped(fragment); + } else { + this._renderUngrouped(fragment); + } + this.$el.append(fragment); } - this.$el.append(fragment); + return this._super.apply(this, arguments).then(_.invoke.bind(_, oldWidgets, 'destroy')); }, + /** + * Sets the current state and updates some internal attributes accordingly. + * + * @private + * @param {Object} state + */ + _setState: function (state) { + this.state = state; + + var groupByFieldAttrs = state.fields[state.groupedBy[0]]; + var groupByFieldInfo = state.fieldsInfo.kanban[state.groupedBy[0]]; + // Deactivate the drag'n'drop if the groupedBy field: + // - is a date or datetime since we group by month or + // - is readonly + var draggable = true; + if (groupByFieldAttrs) { + if (groupByFieldAttrs.type === "date" || groupByFieldAttrs.type === "datetime") { + draggable = false; + } else if (groupByFieldAttrs.readonly !== undefined) { + draggable = !(groupByFieldAttrs.readonly); + } + } + this.groupedByM2O = groupByFieldAttrs && (groupByFieldAttrs.type === 'many2one'); + var grouped_by_field = this.groupedByM2O && groupByFieldAttrs.relation; + var groupByTooltip = groupByFieldInfo && groupByFieldInfo.options.group_by_tooltip; + this.columnOptions = _.extend(this.columnOptions, { + draggable: draggable, + group_by_tooltip: groupByTooltip, + grouped_by_m2o: this.groupedByM2O, + relation: grouped_by_field, + }); + this.createColumnEnabled = this.groupedByM2O && this.columnOptions.group_creatable; + }, }); return KanbanRenderer; diff --git a/addons/web/static/src/js/views/list/list_controller.js b/addons/web/static/src/js/views/list/list_controller.js index 2ec9cf3181e..3b74f140e4d 100644 --- a/addons/web/static/src/js/views/list/list_controller.js +++ b/addons/web/static/src/js/views/list/list_controller.js @@ -188,7 +188,6 @@ var ListController = BasicController.extend({ position: self.editable, }); }).then(function (recordID) { - self._toggleNoContentHelper(false); var state = self.model.get(self.handle); self.renderer.updateState(state, {}); self.renderer.editRecord(recordID); @@ -283,12 +282,10 @@ var ListController = BasicController.extend({ }, /** * @override - * @param {Object} state * @returns {Deferred} */ - _update: function (state) { + _update: function () { this.selectedRecords = []; - this._toggleNoContentHelper(!this._hasContent(state)); this._toggleSidebar(); return this._super.apply(this, arguments); }, diff --git a/addons/web/static/src/js/views/list/list_renderer.js b/addons/web/static/src/js/views/list/list_renderer.js index 802f2f03a09..295266db276 100644 --- a/addons/web/static/src/js/views/list/list_renderer.js +++ b/addons/web/static/src/js/views/list/list_renderer.js @@ -30,7 +30,6 @@ var FIELD_CLASSES = { }; var ListRenderer = BasicRenderer.extend({ - className: 'table-responsive', events: { 'click tbody tr': '_onRowClicked', 'click tbody .o_list_record_selector': '_onSelectRecord', @@ -577,12 +576,24 @@ var ListRenderer = BasicRenderer.extend({ _renderView: function () { var self = this; + this.$el + .removeClass('table-responsive') + .empty(); + // destroy the previously instantiated pagers, if any _.invoke(this.pagers, 'destroy'); this.pagers = []; + // display the no content helper if there is no data to display + if (!this._hasContent() && this.noContentHelp) { + this._renderNoContentHelper(); + return this._super(); + } + var $table = $('<table>').addClass('o_list_view table table-condensed table-striped'); - this.$el.empty().append($table); + this.$el + .addClass('table-responsive') + .append($table); var is_grouped = !!this.state.groupedBy.length; this._computeAggregates(); $table.toggleClass('o_list_view_grouped', is_grouped); diff --git a/addons/web/static/src/js/views/pivot/pivot_controller.js b/addons/web/static/src/js/views/pivot/pivot_controller.js index 78640a97124..731183e7efe 100644 --- a/addons/web/static/src/js/views/pivot/pivot_controller.js +++ b/addons/web/static/src/js/views/pivot/pivot_controller.js @@ -170,21 +170,8 @@ var PivotController = AbstractController.extend({ /** * @private */ - _update: function (state) { + _update: function () { this._updateButtons(); - var hasNoContent = !state.has_data || !state.measures.length; - - if (hasNoContent) { - if (!this.$('.oe_view_nocontent').length) { - this.renderer.$el.detach(); - this.$el.append(QWeb.render('PivotView.nodata')); - } - } else { - if (!document.contains(this.renderer.el)) { - this.$('div.oe_view_nocontent').remove(); - this.$el.append(this.renderer.$el); - } - } return this._super.apply(this, arguments); }, /** diff --git a/addons/web/static/src/js/views/pivot/pivot_renderer.js b/addons/web/static/src/js/views/pivot/pivot_renderer.js index a37e65b104b..d279d59d4b1 100644 --- a/addons/web/static/src/js/views/pivot/pivot_renderer.js +++ b/addons/web/static/src/js/views/pivot/pivot_renderer.js @@ -2,8 +2,11 @@ odoo.define('web.PivotRenderer', function (require) { "use strict"; var AbstractRenderer = require('web.AbstractRenderer'); +var core = require('web.core'); var field_utils = require('web.field_utils'); +var QWeb = core.qweb; + var PivotRenderer = AbstractRenderer.extend({ tagName: 'table', className: 'table-hover table-condensed table-bordered', @@ -16,14 +19,31 @@ var PivotRenderer = AbstractRenderer.extend({ //-------------------------------------------------------------------------- /** + * Used to determine whether or not to display the no content helper. + * + * @private + * @returns {boolean} + */ + _hasContent: function () { + return this.state.has_data && this.state.measures.length; + }, + /** * @override * @private * @returns {Deferred} */ _render: function () { - if (!this.state.has_data) { + if (!this._hasContent()) { + // display the nocontent helper + this.replaceElement(QWeb.render('PivotView.nodata')); return this._super.apply(this, arguments); } + + if (!this.$el.is('table')) { + // coming from the no content helper, so the root element has to be + // re-rendered before rendering and appending its content + this.renderElement(); + } var $fragment = $(document.createDocumentFragment()); var $table = $('<table>').appendTo($fragment); var $thead = $('<thead>').appendTo($table); |
