summaryrefslogtreecommitdiff
path: root/addons/web/static/src/js/chrome
diff options
context:
space:
mode:
authorJulien Mougenot <jum@odoo.com>2020-03-11 09:38:28 +0000
committerJulien Mougenot <jum@odoo.com>2020-03-13 14:08:33 +0000
commitfbf347498f1cc7b74ef373179b7bcae201715c24 (patch)
treeb8d1eb29ec93b6c2e43dbade712e636d32fe6716 /addons/web/static/src/js/chrome
parent0a129284e4856b6485c48a194fd86c3ab5c736e7 (diff)
[REF] web: Control panel Owl
Refactoring of the control panel with the Owl framework. The MVC structure of the control panel has been changed to a 'component <-> model' relationship. As such: - Removed the old control panel: view/model/controller/renderer - Created a new Owl Component (ControlPanel) - Created a new class: the Model (an Owl Store did not fit here) and a newly designed ControlPanelModel extending it Refactored all inner subcomponents, including: - Pager - ActionMenus (peviously SideBar) - Filter menu > Custom filter item - Group by menu > Custom group by item > Removal of groupby_menu_mixin (and refactored graph controller in sibling commit) - Time range menu - Favorite menu > Custom favorite item > Moved the favorite menu registry to the favorite_menu file - Search bar > Removed and splitted auto-completion dropdown logic between the new SearchBar Component (descriptions) and to the new ControlPanelModel (domains). The templates (all in web/base.xml) have been adapted to the new standards. Most of the DOM structure remains unchanged with some occasional improvements (replace hiding with not rendering, removed pointless wrapper divs, etc.). Part of task 2196029 Co-authored-by: Mathieu Duckerts-Antoine <dam@odoo.com>
Diffstat (limited to 'addons/web/static/src/js/chrome')
-rw-r--r--addons/web/static/src/js/chrome/pager.js276
-rw-r--r--addons/web/static/src/js/chrome/sidebar.js219
2 files changed, 0 insertions, 495 deletions
diff --git a/addons/web/static/src/js/chrome/pager.js b/addons/web/static/src/js/chrome/pager.js
deleted file mode 100644
index 86700d93374..00000000000
--- a/addons/web/static/src/js/chrome/pager.js
+++ /dev/null
@@ -1,276 +0,0 @@
-odoo.define('web.Pager', function (require) {
-"use strict";
-
-var utils = require('web.utils');
-var Widget = require('web.Widget');
-
-var direction = {
- previous: -1,
- next: 1,
-};
-
-var Pager = Widget.extend({
- template: "Pager",
- events: {
- 'click .o_pager_next': '_onNext',
- 'click .o_pager_previous': '_onPrevious',
- 'click .o_pager_value': '_onEdit',
- },
- /**
- * The pager goes from 1 to size (included).
- * The current value is current_min if limit === 1
- * or the interval [current_min, current_min + limit[ if limit > 1
- *
- * @param {Widget} [parent] the parent widget
- * @param {int} [size] the total number of elements
- * @param {int} [current_min] the first element of the current_page
- * @param {int} [limit] the number of elements per page
- * @param {boolean} [options.can_edit] editable feature of the pager
- * @param {boolean} [options.single_page_hidden] (not) to display the pager
- * if only one page
- * @param {function} [options.validate] callback returning a Promise to
- * validate changes
- */
- init: function (parent, size, current_min, limit, options) {
- this.state = {
- size: size,
- current_min: current_min,
- limit: limit,
- };
- Object.defineProperty(this.state, 'current_max', {
- get: function() {
- return Math.min(this.current_min + this.limit - 1, this.size);
- }
- });
- this.options = _.defaults({}, options, {
- can_edit: true, // editable
- single_page_hidden: false, // displayed even if there is a single page
- validate: function() {
- return Promise.resolve();
- },
- withAccessKey: true, // can be disabled, for example, for x2m widgets
- });
- this._super(parent);
- },
- /**
- * Renders the pager
- *
- * @returns {Promise}
- */
- start: function () {
- this.$value = this.$('.o_pager_value');
- this.$limit = this.$('.o_pager_limit');
- this._render();
- return this._super();
- },
-
- //--------------------------------------------------------------------------
- // Public
- //--------------------------------------------------------------------------
-
- /**
- * Disables the pager's arrows and the edition
- */
- disable: function () {
- this.disabled = true;
- this._updateArrows();
- },
- /**
- * Enables the pager's arrows and the edition
- */
- enable: function () {
- this.disabled = false;
- this._updateArrows();
- },
- /**
- * Executes the next action on the pager
- */
- next: function () {
- this._changeSelection(direction.next);
- },
- /**
- * Executes the previous action on the pager
- */
- previous: function () {
- this._changeSelection(direction.previous);
- },
- /**
- * Sets the state of the pager and renders it
- * @param {Object} [state] the values to update (size, current_min and limit)
- * @param {Object} [options]
- * @param {boolean} [options.notifyChange] set to true to make the pager
- * notify the environment that its state changed
- */
- updateState: function (state, options) {
- _.extend(this.state, state);
- this._render();
- if (options && options.notifyChange) {
- this.trigger('pager_changed', _.clone(this.state));
- }
- },
-
- //--------------------------------------------------------------------------
- // Private
- //--------------------------------------------------------------------------
-
- /**
- * Private function that updates the pager's state according to a pager action
- *
- * @param {int} [direction] the action (previous or next) on the pager
- */
- _changeSelection: function (direction) {
- var self = this;
- this.options.validate().then(function() {
- var size = self.state.size;
- var current_min = self.state.current_min;
- var limit = self.state.limit;
-
- // Compute the new current_min
- current_min = (current_min + limit*direction);
- if (current_min > size) {
- current_min = 1;
- } else if ((current_min < 1) && (limit === 1)) {
- current_min = size;
- } else if ((current_min < 1) && (limit > 1)) {
- current_min = size - ((size % limit) || limit) + 1;
- }
-
- self.state.current_min = current_min;
- // The re-rendering of the pager must be done before the trigger of
- // event 'pager_changed' as the rendering may enable the pager
- // (and a common use is to disable the pager when this event is
- // triggered, and to re-enable it when the data have been reloaded)
- self._render();
- self.trigger('pager_changed', _.clone(self.state));
- });
- },
- /**
- * Private function that displays an input to edit the pager's state
- */
- _edit: function () {
- if (this.options.can_edit) {
- var self = this;
- var $input = $('<input>', {class: 'o_input', type: 'text', value: this.$value.html()});
-
- this.$value.html($input);
- $input.focus();
-
- // Event handlers
- $input.click(function(ev) {
- ev.stopPropagation(); // ignore clicks on the input
- });
- $input.blur(function(ev) {
- self._save($(ev.target)); // save the state when leaving the input
- });
- $input.on('keydown', function (ev) {
- ev.stopPropagation();
- if (ev.which === $.ui.keyCode.ENTER) {
- self._save($(ev.target)); // save on enter
- } else if (ev.which === $.ui.keyCode.ESCAPE) {
- self._render(); // leave on escape
- }
- });
- }
- },
- /**
- * Private function that renders the pager's state
- */
- _render: function () {
- var size = this.state.size;
- var current_min = this.state.current_min;
- var current_max = this.state.current_max;
-
- if (size === 0 || (this.options.single_page_hidden && this._singlePage())) {
- this.do_hide();
- } else {
- this.do_show();
- this._updateArrows();
-
- var value = "" + current_min;
- if (this.state.limit > 1) {
- value += "-" + current_max;
- }
- this.$value.html(value);
- this.$limit.html(size);
- }
- },
- /**
- * Private function that saves the state from the content of the input
- *
- * @param {jQuery} [$input] the jQuery element containing the new state
- */
- _save: function ($input) {
- var self = this;
- this.options.validate().then(function() {
- var value = $input.val().split("-");
- var min = utils.confine(parseInt(value[0], 10), 1, self.state.size);
- var max = utils.confine(parseInt(value[1], 10), 1, self.state.size);
-
- if (!isNaN(min)) {
- self.state.current_min = min;
- if (!isNaN(max)) {
- self.state.limit = utils.confine(max-min+1, 1, self.state.size);
- } else {
- // The state has been given as a single value -> set the limit to 1
- self.state.limit = 1;
- }
- self.trigger('pager_changed', _.clone(self.state));
- }
- // Render the pager's new state (removes the input)
- self._render();
- });
- },
- /**
- * @private
- * @returns {boolean} true iff there is only one page
- */
- _singlePage: function () {
- var state = this.state;
- return (1 === state.current_min) && (state.current_max === state.size);
- },
- /**
- * Updates the arrows' disable attribute: true iff the pager is disabed or
- * if there is only one page
- *
- * @private
- */
- _updateArrows: function () {
- var disabled = this.disabled || this._singlePage();
- this.$('button').prop('disabled', disabled);
- },
-
- //--------------------------------------------------------------------------
- // Handlers
- //--------------------------------------------------------------------------
-
- /**
- * @private
- * @param {MouseEvent} event
- */
- _onEdit: function (event) {
- event.stopPropagation();
- if (!this.disabled) {
- this._edit();
- }
- },
- /**
- * @private
- * @param {MouseEvent} event
- */
- _onNext: function (event) {
- event.stopPropagation();
- this.next();
- },
- /**
- * @private
- * @param {MouseEvent} event
- */
- _onPrevious: function (event) {
- event.stopPropagation();
- this.previous();
- },
-});
-
-return Pager;
-
-});
diff --git a/addons/web/static/src/js/chrome/sidebar.js b/addons/web/static/src/js/chrome/sidebar.js
deleted file mode 100644
index ce24bf31f60..00000000000
--- a/addons/web/static/src/js/chrome/sidebar.js
+++ /dev/null
@@ -1,219 +0,0 @@
-odoo.define('web.Sidebar', function (require) {
-"use strict";
-
-var Context = require('web.Context');
-var core = require('web.core');
-var pyUtils = require('web.py_utils');
-var Widget = require('web.Widget');
-
-var QWeb = core.qweb;
-var _t = core._t;
-
-var Sidebar = Widget.extend({
- events: {
- "click a.dropdown-item": "_onDropdownClicked"
- },
- /**
- * @override
- *
- * @param {Object} options
- * @param {Object} options.items
- * @param {Object} options.sections
- * @param {Object} options.env
- * @param {Object} options.actions
- *
- */
- init: function (parent, options) {
- this._super.apply(this, arguments);
- this.options = _.defaults(options || {}, {
- 'editable': true
- });
- this.env = options.env;
- this.sections = options.sections || [
- {name: 'print', label: _t('Print')},
- {name: 'other', label: _t('Action')},
- ];
- this.items = options.items || {
- print: [],
- other: [],
- };
- if (options.actions) {
- this._addToolbarActions(options.actions);
- }
- },
- /**
- * @override
- */
- start: function () {
- this._super.apply(this, arguments);
- this.$el.addClass('btn-group');
- this._redraw();
- },
-
- //--------------------------------------------------------------------------
- // Public
- //--------------------------------------------------------------------------
-
- /**
- * Update the env for the sidebar then rerender it.
- *
- * @param {Object} env
- */
- updateEnv: function (env) {
- this.env = env;
- this._redraw();
- },
-
- //--------------------------------------------------------------------------
- // Private
- //--------------------------------------------------------------------------
-
- /**
- * For each item added to the section:
- *
- * ``label``
- * will be used as the item's name in the sidebar, can be html
- *
- * ``action``
- * descriptor for the action which will be executed, ``action`` and
- * ``callback`` should be exclusive
- *
- * ``callback``
- * function to call when the item is clicked in the sidebar, called
- * with the item descriptor as its first argument (so information
- * can be stored as additional keys on the object passed to
- * ``_addItems``)
- *
- * ``classname`` (optional)
- * ``@class`` set on the sidebar serialization of the item
- *
- * ``title`` (optional)
- * will be set as the item's ``@title`` (tooltip)
- *
- * @private
- * @param {String} sectionCode
- * @param {Array<{label, action | callback[, classname][, title]}>} items
- */
- _addItems: function (sectionCode, items) {
- if (items) {
- this.items[sectionCode].unshift.apply(this.items[sectionCode], items);
- }
- },
- /**
- * Method that will add the custom actions to the toolbar
- *
- * @private
- * @param {Object} toolbarActions
- */
- _addToolbarActions: function (toolbarActions) {
- var self = this;
- _.each(['print','action','relate'], function (type) {
- if (type in toolbarActions) {
- var actions = toolbarActions[type];
- if (actions && actions.length) {
- var items = _.map(actions, function (action) {
- return {
- label: action.name,
- action: action,
- };
- });
- self._addItems(type === 'print' ? 'print' : 'other', items);
- }
- }
- });
- if ('other' in toolbarActions) {
- this._addItems('other', toolbarActions.other);
- }
- },
- /**
- * Performs the action for the item clicked after getting the data
- * necessary with a trigger up
- *
- * @private
- * @param {Object} item
- */
- _onItemActionClicked: function (item) {
- var self = this;
- this.trigger_up('sidebar_data_asked', {
- callback: function (env) {
- self.env = env;
- var activeIdsContext = {
- active_id: env.activeIds[0],
- active_ids: env.activeIds,
- active_model: env.model,
- select_all: !!env.selectAll,
- };
- if (env.domain) {
- activeIdsContext.active_domain = env.domain;
- }
-
- var context = pyUtils.eval('context', new Context(env.context, activeIdsContext));
- self._rpc({
- route: '/web/action/load',
- params: {
- action_id: item.action.id,
- context: context,
- },
- }).then(function (result) {
- result.context = new Context(
- result.context || {}, activeIdsContext)
- .set_eval_context(context);
- result.flags = result.flags || {};
- result.flags.new_window = true;
- self.do_action(result, {
- on_close: function () {
- self.trigger_up('reload');
- },
- });
- });
- }
- });
- },
- /**
- * Method that renders the sidebar when there is a data update
- *
- * @private
- */
- _redraw: function () {
- this.$el.html(QWeb.render('Sidebar', {widget: this}));
-
- // Hides Sidebar sections when item list is empty
- _.each(this.$('.o_dropdown'), function (el) {
- var $dropdown = $(el);
- if (!$dropdown.find('.dropdown-item').length) {
- $dropdown.hide();
- }
- });
- this.$("[title]").tooltip({
- delay: { show: 500, hide: 0}
- });
- },
-
- //--------------------------------------------------------------------------
- // Handlers
- //--------------------------------------------------------------------------
-
- /**
- * Method triggered when the user clicks on a toolbar dropdown
- *
- * @private
- * @param {MouseEvent} event
- */
- _onDropdownClicked: function (event) {
- var section = $(event.currentTarget).data('section');
- var index = $(event.currentTarget).data('index');
- var item = this.items[section][index];
- if (item.callback) {
- item.callback.apply(this, [item]);
- } else if (item.action) {
- this._onItemActionClicked(item);
- } else if (item.url) {
- return true;
- }
- event.preventDefault();
- },
-});
-
-return Sidebar;
-
-});