summaryrefslogtreecommitdiff
path: root/addons/web/static/src/js/views/pivot/pivot_renderer.js
diff options
context:
space:
mode:
authorstephanchrst <stephanchrst@gmail.com>2022-05-10 21:51:50 +0700
committerstephanchrst <stephanchrst@gmail.com>2022-05-10 21:51:50 +0700
commit3751379f1e9a4c215fb6eb898b4ccc67659b9ace (patch)
treea44932296ef4a9b71d5f010906253d8c53727726 /addons/web/static/src/js/views/pivot/pivot_renderer.js
parent0a15094050bfde69a06d6eff798e9a8ddf2b8c21 (diff)
initial commit 2
Diffstat (limited to 'addons/web/static/src/js/views/pivot/pivot_renderer.js')
-rw-r--r--addons/web/static/src/js/views/pivot/pivot_renderer.js202
1 files changed, 202 insertions, 0 deletions
diff --git a/addons/web/static/src/js/views/pivot/pivot_renderer.js b/addons/web/static/src/js/views/pivot/pivot_renderer.js
new file mode 100644
index 00000000..dcba95bc
--- /dev/null
+++ b/addons/web/static/src/js/views/pivot/pivot_renderer.js
@@ -0,0 +1,202 @@
+odoo.define('web.PivotRenderer', function (require) {
+ "use strict";
+
+ const OwlAbstractRenderer = require('web.AbstractRendererOwl');
+ const field_utils = require('web.field_utils');
+ const patchMixin = require('web.patchMixin');
+
+ const { useExternalListener, useState, onMounted, onPatched } = owl.hooks;
+
+ /**
+ * Here is a basic example of the structure of the Pivot Table:
+ *
+ * ┌─────────────────────────┬─────────────────────────────────────────────┬─────────────────┐
+ * │ │ - web.PivotHeader │ │
+ * │ ├──────────────────────┬──────────────────────┤ │
+ * │ │ + web.PivotHeader │ + web.PivotHeader │ │
+ * ├─────────────────────────┼──────────────────────┼──────────────────────┼─────────────────┤
+ * │ │ web.PivotMeasure │ web.PivotMeasure │ │
+ * ├─────────────────────────┼──────────────────────┼──────────────────────┼─────────────────┤
+ * │ ─ web.PivotHeader │ │ │ │
+ * ├─────────────────────────┼──────────────────────┼──────────────────────┼─────────────────┤
+ * │ + web.PivotHeader │ │ │ │
+ * ├─────────────────────────┼──────────────────────┼──────────────────────┼─────────────────┤
+ * │ + web.PivotHeader │ │ │ │
+ * └─────────────────────────┴──────────────────────┴──────────────────────┴─────────────────┘
+ *
+ */
+
+ class PivotRenderer extends OwlAbstractRenderer {
+ /**
+ * @override
+ * @param {boolean} props.disableLinking Disallow opening records by clicking on a cell
+ * @param {Object} props.widgets Widgets defined in the arch
+ */
+ constructor() {
+ super(...arguments);
+ this.sampleDataTargets = ['table'];
+ this.state = useState({
+ activeNodeHeader: {
+ groupId: false,
+ isXAxis: false,
+ click: false
+ },
+ });
+
+ onMounted(() => this._updateTooltip());
+
+ onPatched(() => this._updateTooltip());
+
+ useExternalListener(window, 'click', this._resetState);
+ }
+
+ //----------------------------------------------------------------------
+ // Private
+ //----------------------------------------------------------------------
+
+ /**
+ * Get the formatted value of the cell
+ *
+ * @private
+ * @param {Object} cell
+ * @returns {string} Formatted value
+ */
+ _getFormattedValue(cell) {
+ const type = this.props.widgets[cell.measure] ||
+ (this.props.fields[cell.measure].type === 'many2one' ? 'integer' : this.props.fields[cell.measure].type);
+ const formatter = field_utils.format[type];
+ return formatter(cell.value, this.props.fields[cell.measure]);
+ }
+
+ /**
+ * Get the formatted variation of a cell
+ *
+ * @private
+ * @param {Object} cell
+ * @returns {string} Formatted variation
+ */
+ _getFormattedVariation(cell) {
+ const value = cell.value;
+ return isNaN(value) ? '-' : field_utils.format.percentage(value, this.props.fields[cell.measure]);
+ }
+
+ /**
+ * Retrieves the padding of a left header
+ *
+ * @private
+ * @param {Object} cell
+ * @returns {Number} Padding
+ */
+ _getPadding(cell) {
+ return 5 + cell.indent * 30;
+ }
+
+ /**
+ * Compute if a cell is active (with its groupId)
+ *
+ * @private
+ * @param {Array} groupId GroupId of a cell
+ * @param {Boolean} isXAxis true if the cell is on the x axis
+ * @returns {Boolean} true if the cell is active
+ */
+ _isClicked(groupId, isXAxis) {
+ return _.isEqual(groupId, this.state.activeNodeHeader.groupId) && this.state.activeNodeHeader.isXAxis === isXAxis;
+ }
+
+ /**
+ * Reset the state of the node.
+ *
+ * @private
+ */
+ _resetState() {
+ // This check is used to avoid the destruction of the dropdown.
+ // The click on the header bubbles to window in order to hide
+ // all the other dropdowns (in this component or other components).
+ // So we need isHeaderClicked to cancel this behaviour.
+ if (this.isHeaderClicked) {
+ this.isHeaderClicked = false;
+ return;
+ }
+ this.state.activeNodeHeader = {
+ groupId: false,
+ isXAxis: false,
+ click: false
+ };
+ }
+
+ /**
+ * Configure the tooltips on the headers.
+ *
+ * @private
+ */
+ _updateTooltip() {
+ $(this.el).find('.o_pivot_header_cell_opened, .o_pivot_header_cell_closed').tooltip();
+ }
+
+ //----------------------------------------------------------------------
+ // Handlers
+ //----------------------------------------------------------------------
+
+
+ /**
+ * Handles a click on a menu item in the dropdown to select a groupby.
+ *
+ * @private
+ * @param {Object} field
+ * @param {string} interval
+ */
+ _onClickMenuGroupBy(field, interval) {
+ this.trigger('groupby_menu_selection', { field, interval });
+ }
+
+
+ /**
+ * Handles a click on a header node
+ *
+ * @private
+ * @param {Object} cell
+ * @param {string} type col or row
+ */
+ _onHeaderClick(cell, type) {
+ const groupValues = cell.groupId[type === 'col' ? 1 : 0];
+ const groupByLength = type === 'col' ? this.props.colGroupBys.length : this.props.rowGroupBys.length;
+ if (cell.isLeaf && groupValues.length >= groupByLength) {
+ this.isHeaderClicked = true;
+ this.state.activeNodeHeader = {
+ groupId: cell.groupId,
+ isXAxis: type === 'col',
+ click: 'leftClick'
+ };
+ }
+ this.trigger(cell.isLeaf ? 'closed_header_click' : 'opened_header_click', { cell, type });
+ }
+
+ /**
+ * Hover the column in which the mouse is.
+ *
+ * @private
+ * @param {MouseEvent} ev
+ */
+ _onMouseEnter(ev) {
+ var index = [...ev.currentTarget.parentNode.children].indexOf(ev.currentTarget);
+ if (ev.currentTarget.tagName === 'TH') {
+ index += 1;
+ }
+ this.el.querySelectorAll('td:nth-child(' + (index + 1) + ')').forEach(elt => elt.classList.add('o_cell_hover'));
+ }
+
+ /**
+ * Remove the hover on the columns.
+ *
+ * @private
+ */
+ _onMouseLeave() {
+ this.el.querySelectorAll('.o_cell_hover').forEach(elt => elt.classList.remove('o_cell_hover'));
+ }
+ }
+
+ PivotRenderer.template = 'web.PivotRenderer';
+
+ return patchMixin(PivotRenderer);
+
+});