From 11de0f36ed923f0222d8e1ecc603b53366eabf75 Mon Sep 17 00:00:00 2001 From: Gery Debongnie Date: Tue, 14 Jan 2014 13:51:42 +0100 Subject: [REF] separates graph view and graph widget into two files, and renames pivot into pivot_table.js (addon web_graph) bzr revid: ged@openerp.com-20140114125142-9qj3mvu0a1fp4sis --- addons/web_graph/static/src/js/pivot_table.js | 539 ++++++++++++++++++++++++++ 1 file changed, 539 insertions(+) create mode 100644 addons/web_graph/static/src/js/pivot_table.js (limited to 'addons/web_graph/static/src/js/pivot_table.js') diff --git a/addons/web_graph/static/src/js/pivot_table.js b/addons/web_graph/static/src/js/pivot_table.js new file mode 100644 index 00000000000..9c927150f20 --- /dev/null +++ b/addons/web_graph/static/src/js/pivot_table.js @@ -0,0 +1,539 @@ + +/* jshint undef: false */ + +(function () { +'use strict'; + +// Pivot Table emits the events 'groupby_changed' and 'redraw_required' when necessary. +// PivotTable is initialized by default 'inactive', and require a call to activate() +// after init to load initial data and start triggering events. +openerp.web_graph.PivotTable = openerp.web.Class.extend(openerp.EventDispatcherMixin, { + + init: function (model, domain, fields, options) { + openerp.EventDispatcherMixin.init.call(this); + this.cells = []; + this.domain = domain; + this.no_data = true; + this.model = model; + this.fields = fields; + this.fields.__count = {type: 'integer', string:'Quantity'}; + this.measures = [{field:'__count', type: this.fields.type, string:this.fields.string}]; + this.active = false; + this.rows = { groupby: this.create_field_values(options.row_groupby || []), headers: null }; + this.cols = { groupby: this.create_field_values(options.col_groupby || []), headers: null }; + if (options.measures) { this.set_measures(options.measures); } + }, + + // ---------------------------------------------------------------------- + // Configuration methods + // ---------------------------------------------------------------------- + // this.measures: list of measure [measure], measure = {field: _, string: _, type: _} + // this.rows.groupby, this.cols.groupby : list of groupbys used for describing rows (...), + // a groupby is also {field:_, string:_, type:_} but it also has a interval + // attribute if its type is date/datetime. + // this.active: If PivotTable is active then it triggers events and updates + // its values when necessary + activate: function() { + this.active = true; + this.update_data(); + }, + + set_measures: function (measures) { + var self = this; + if (!_.isEqual(measures, this.measures)) { + this.measures = []; + _.each(measures, function (m) { self._add_measure(m); }); + if (this.active) { this.update_data(); } + } + }, + + _add_measure: function (measure) { + if (measure.field && measure.string && measure.type) { + this.measures.push(measure); + } else { + this.measures.push({ + field: measure, + string: this.fields[measure].string, + type: this.fields[measure].type, + }); + } + }, + + toggle_measure: function (field_id) { + var current_measure = _.findWhere(this.measures, {field:field_id}); + if (current_measure) { + this.measures = _.without(this.measures, current_measure); + } else { + this.measures.push({ + field: field_id, + type: this.fields[field_id].type, + string: this.fields[field_id].string + }); + } + if (this.active) { this.update_data(); } + }, + + set: function (domain, row_groupby, col_groupby) { + var row_gbs = this.create_field_values(row_groupby), + col_gbs = this.create_field_values(col_groupby), + dom_changed = !_.isEqual(this.domain, domain), + gb_changed = !(_.isEqual(row_gbs, this.rows.groupby) && + _.isEqual(col_gbs, this.cols.groupby)); + + if (dom_changed) { + this.domain = domain; + } + if (gb_changed) { + this.cols.groupby = col_gbs; + this.rows.groupby = row_gbs; + if (this.active) { this.trigger('groupby_changed'); } + } + if (this.active && (gb_changed || dom_changed)) { + this.update_data(); + } + }, + + create_field_value: function (f) { + if (f.field && f.interval) { + return { field:f.field, + string: this.fields[f.field].string, + type:this.fields[f.field].type, + interval: f.interval }; + } + return (f.field && f.string && f.type) ? f : { field: f, + string: this.fields[f].string, + type: this.fields[f].type }; + }, + + create_field_values: function (field_ids) { + var self = this; + return _.map(field_ids, function (f) { return self.create_field_value(f); }); + }, + + _add_groupby: function(groupby_list, groupby) { + groupby_list.push(this.create_field_value(groupby)); + }, + + // ---------------------------------------------------------------------- + // Cells manipulation methods + // ---------------------------------------------------------------------- + // cells are objects {x:_, y:_, values:_} where x < y and values is an array + // of values (one for each measure). The condition x < y might look + // unnecessary, but it makes the rest of the code simpler: headers + // don't krow if they are rows or cols, they just know their id, so + // it is useful that a call get_values(id1, id2) is the same as get_values(id2, id1) + add_cell : function (id1, id2, values) { + this.cells.push({x: Math.min(id1, id2), y: Math.max(id1, id2), values: values}); + }, + + get_values: function (id1, id2, default_values) { + var cell = _.find(this.cells, function (c) { + return ((c.x == Math.min(id1, id2)) && (c.y == Math.max(id1, id2))); + }); + return (cell !== undefined) ? cell.values : (default_values || new Array(this.measures.length)); + }, + + // ---------------------------------------------------------------------- + // Headers/Rows/Cols manipulation methods + // ---------------------------------------------------------------------- + // this.rows.headers, this.cols.headers = [header] describe the tree structure + // of rows/cols. Headers are objects + // { + // id:_, (unique id obviously) + // path: [...], (array of all parents title, with its own title at the end) + // title:_, (name of the row/col) + // children:[_], (subrows or sub cols of this row/col) + // domain:_, (domain of data in this row/col) + // root:_ (ref to this.rows or this.cols corresponding to the header) + // expanded:_ (boolean, true if it has been expanded) + // } + is_row: function (id) { + return !!_.find(this.rows.headers, function (header) { + return header.id === id; + }); + }, + + is_col: function (id) { + return !!_.find(this.cols.headers, function (header) { + return header.id === id; + }); + }, + + get_header: function (id) { + return _.find(this.rows.headers.concat(this.cols.headers), function (header) { + return header.id === id; + }); + }, + + // return all columns with a path length of 'depth' + get_cols_with_depth: function (depth) { + return _.filter(this.cols.headers, function (header) { + return header.path.length === depth; + }); + }, + + // return all rows with a path length of 'depth' + get_rows_with_depth: function (depth) { + return _.filter(this.rows.headers, function (header) { + return header.path.length === depth; + }); + }, + + // return all non expanded rows + get_rows_leaves: function () { + return _.filter(this.rows.headers, function (header) { + return !header.expanded; + }); + }, + + // return all non expanded cols + get_cols_leaves: function () { + return _.filter(this.cols.headers, function (header) { + return !header.expanded; + }); + }, + + get_ancestors: function (header) { + var self = this; + if (!header.children) return []; + return [].concat.apply([], _.map(header.children, function (c) {return self.get_ancestors_and_self(c); })); + }, + + get_ancestors_and_self: function (header) { + var self = this; + return [].concat.apply([header], _.map(header.children, function (c) { return self.get_ancestors_and_self(c); })); + }, + + get_total: function (header) { + if (header) { + return this.get_values(header.id, this.get_other_root(header).headers[0].id); + } + return this.get_values(this.rows.headers[0].id, this.cols.headers[0].id); + }, + + get_other_root: function (header) { + return (header.root === this.rows) ? this.cols : this.rows; + }, + + main_row: function () { return this.rows.headers[0]; }, + + main_col: function () { return this.cols.headers[0]; }, + + // ---------------------------------------------------------------------- + // Table manipulation methods : fold/expand/swap + // ---------------------------------------------------------------------- + fold: function (header) { + var ancestors = this.get_ancestors(header), + removed_ids = _.pluck(ancestors, 'id'); + + header.root.headers = _.difference(header.root.headers, ancestors); + header.children = []; + header.expanded = false; + + this.cells = _.reject(this.cells, function (cell) { + return (_.contains(removed_ids, cell.x) || _.contains(removed_ids, cell.y)); + }); + + var new_groupby_length = _.max(_.map(header.root.headers, function(g) {return g.path.length;})); + if (new_groupby_length < header.root.groupby.length) { + header.root.groupby.splice(new_groupby_length); + this.trigger('groupby_changed'); + } + this.trigger('redraw_required'); + }, + + expand: function (header_id, groupby) { + var self = this, + header = this.get_header(header_id), + otherRoot = this.get_other_root(header), + fields = otherRoot.groupby.concat(this.measures); + + if (header.path.length === header.root.groupby.length) { + self._add_groupby(header.root.groupby, groupby); + this.trigger('groupby_changed'); + } + groupby = [header.root.groupby[header.path.length]].concat(otherRoot.groupby); + + return this.get_groups(groupby, fields, header.domain) + .then(function (groups) { + _.each(groups.reverse(), function (group) { + // make header + var child = self.make_header(group, header); + child.expanded = false; + header.children.splice(0,0, child); + header.root.headers.splice(header.root.headers.indexOf(header) + 1, 0, child); + // make cells + _.each(self.get_ancestors_and_self(group), function (data) { + var values = _.map(self.measures, function (m) { + return data.attributes.aggregates[m.field]; + }); + var other = _.find(otherRoot.headers, function (h) { + if (header.root === self.cols) { + return _.isEqual(data.path.slice(1), h.path); + } else { + return _.isEqual(_.rest(data.path), h.path); + } + }); + if (other) { + self.add_cell(child.id, other.id, values); + } + }); + }); + header.expanded = true; + self.trigger('redraw_required'); + }); + }, + + make_header: function (group, parent) { + var title = parent ? group.attributes.value : ''; + return { + id: _.uniqueId(), + path: parent ? parent.path.concat(title) : [], + title: title, + children: [], + domain: parent ? group.model._domain : this.domain, + root: parent ? parent.root : undefined, + }; + }, + + swap_axis: function () { + var temp = this.rows; + this.rows = this.cols; + this.cols = temp; + this.trigger('groupby_changed'); + this.trigger('redraw_required'); + }, + + // ---------------------------------------------------------------------- + // Data updating methods + // ---------------------------------------------------------------------- + // Load the data from the db, using the method this.load_data + // update_data will try to preserve the expand/not expanded status of each + // column/row. If you want to expand all, then set this.cols.headers/this.rows.headers + // to null before calling update_data. + update_data: function () { + var self = this; + + return this.load_data().then (function (result) { + if (result) { + self.no_data = false; + self[self.cols.headers ? 'update_headers' : 'expand_headers'](self.cols, result.col_headers); + self[self.rows.headers ? 'update_headers' : 'expand_headers'](self.rows, result.row_headers); + } else { + self.no_data = true; + } + self.trigger('redraw_required'); + }); + }, + + expand_headers: function (root, new_headers) { + root.headers = new_headers; + _.each(root.headers, function (header) { + header.root = root; + header.expanded = (header.children.length > 0); + }); + }, + + update_headers: function (root, new_headers) { + _.each(root.headers, function (header) { + var corresponding_header = _.find(new_headers, function (h) { + return _.isEqual(h.path, header.path); + }); + if (corresponding_header && header.expanded) { + corresponding_header.expanded = true; + _.each(corresponding_header.children, function (c) { + c.expanded = false; + }); + } + if (corresponding_header && (!header.expanded)) { + corresponding_header.expanded = false; + } + }); + var updated_headers = _.filter(new_headers, function (header) { + return (header.expanded !== undefined); + }); + _.each(updated_headers, function (header) { + if (!header.expanded) { + header.children = []; + } + header.root = root; + }); + root.headers = updated_headers; + }, + + expand_all: function () { + this.rows.headers = null; + this.cols.headers = null; + this.update_data(); + }, + + // ---------------------------------------------------------------------- + // Data loading methods + // ---------------------------------------------------------------------- + + // To obtain all the values required to draw the full table, we have to do + // at least 2 + min(row.groupby.length, col.groupby.length) + // calls to readgroup. To simplify the code, we will always do + // 2 + row.groupby.length calls. For example, if row.groupby = [r1, r2, r3] + // and col.groupby = [c1, c2], then we will make the call with the following + // groupbys: [r1,r2,r3], [c1,r1,r2,r3], [c1,c2,r1,r2,r3], []. + load_data: function () { + var self = this, + cols = this.cols.groupby, + rows = this.rows.groupby, + visible_fields = rows.concat(cols, self.measures); + + var groupbys = _.map(_.range(cols.length + 1), function (i) { + return cols.slice(0, i).concat(rows); + }); + groupbys.push([]); + + var def_array = _.map(groupbys, function (groupby) { + return self.get_groups(groupby, visible_fields, self.domain); + }); + + return $.when.apply(null, def_array).then(function () { + var data = Array.prototype.slice.call(arguments), + row_data = data[0], + col_data = (cols.length !== 0) ? data[data.length - 2] : [], + total = data[data.length - 1][0]; + + return (total === undefined) ? undefined + : self.format_data(total, col_data, row_data, data); + }); + }, + + get_groups: function (groupbys, fields, domain, path) { + path = path || []; + var self = this, + groupby = (groupbys.length) ? groupbys[0] : []; + + return this._query_db(groupby, fields, domain, path).then(function (groups) { + if (groupbys.length > 1) { + var get_subgroups = $.when.apply(null, _.map(groups, function (group) { + return self.get_groups(_.rest(groupbys), fields, group.model._domain, path.concat(group.attributes.value)).then(function (subgroups) { + group.children = subgroups; + }); + })); + return get_subgroups.then(function () { + return groups; + }); + } else { + return groups; + } + }); + + }, + + _query_db: function (groupby, fields, domain, path) { + var self = this, + field_ids = _.without(_.pluck(fields, 'field'), '__count'), + context = {}; + + if (groupby.interval) { + context.datetime_format = {}; + var display_format; + switch (groupby.interval) { + case 'day': + display_format = 'dd MMMM YYYY'; + break; + case 'week': + display_format = 'w YYYY'; + break; + case 'month': + display_format = 'MMMM YYYY'; + break; + case 'quarter': + display_format = 'QQQ YYYY'; + break; + case 'year': + display_format = 'YYYY'; + break; + } + context.datetime_format[groupby.field] = { + interval: groupby.interval, + display_format: display_format + }; + } + return this.model.query(field_ids) + .filter(domain) + .context(context) + .group_by(groupby.field) + .then(function (results) { + var groups = _.filter(results, function (group) { + return group.attributes.length > 0; + }); + return _.map(groups, function (g) { return self.format_group(g, path); }); + }); + }, + + // add the path to the group and sanitize the value... + format_group: function (group, current_path) { + var value = group.attributes.value; + + if (group.attributes.grouped_on && this.fields[group.attributes.grouped_on].type === 'selection') { + var selection = this.fields[group.attributes.grouped_on].selection, + value_lookup = _.find(selection, function (val) { return val[0] === value; }); + group.attributes.value = value_lookup ? value_lookup[1] : 'undefined'; + } else if (value === false) { + group.attributes.value = 'undefined'; + } else if (value instanceof Array) { + group.attributes.value = value[1]; + } + + group.path = value ? (current_path || []).concat(group.attributes.value) : []; + group.attributes.aggregates.__count = group.attributes.length; + + return group; + }, + + format_data: function (total, col_data, row_data, cell_data) { + var self = this, + dim_row = this.rows.groupby.length, + dim_col = this.cols.groupby.length, + col_headers = this.get_ancestors_and_self(this.make_headers(col_data, dim_col)), + row_headers = this.get_ancestors_and_self(this.make_headers(row_data, dim_row)); + + this.cells = []; + _.each(cell_data, function (data, index) { + self.make_cells(data, index, [], row_headers, col_headers); + }); // not pretty. make it more functional? + + return {col_headers: col_headers, row_headers: row_headers}; + }, + + make_headers: function (data, depth, parent) { + var self = this, + main = this.make_header(data, parent); + + if (main.path.length < depth) { + main.children = _.map(data.children || data, function (data_pt) { + return self.make_headers (data_pt, depth, main); + }); + } + return main; + }, + + make_cells: function (data, index, current_path, rows, cols) { + var self = this; + _.each(data, function (group) { + var attr = group.attributes, + path = attr.grouped_on ? current_path.concat(attr.value) : current_path, + values = _.map(self.measures, function (measure) { + return (measure.field === '__count') ? attr.length : attr.aggregates[measure.field]; + }); + + var row = _.find(rows, function (header) { return _.isEqual(header.path, path.slice(index)); }); + var col = _.find(cols, function (header) { return _.isEqual(header.path, path.slice(0, index)); }); + self.add_cell(row.id, col.id, values); + + if (group.children) { + self.make_cells (group.children, index, path, rows, cols); + } + }); + }, + +}); +})(); + + -- cgit v1.2.3 From cf81efda4309f895f6777c46c39f1fe894f109cf Mon Sep 17 00:00:00 2001 From: Gery Debongnie Date: Wed, 15 Jan 2014 10:37:49 +0100 Subject: [IMP] adds search view integration in graph view (addon web_graph) bzr revid: ged@openerp.com-20140115093749-t2s0306fchm2tnir --- addons/web_graph/static/src/js/pivot_table.js | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'addons/web_graph/static/src/js/pivot_table.js') diff --git a/addons/web_graph/static/src/js/pivot_table.js b/addons/web_graph/static/src/js/pivot_table.js index 9c927150f20..edd1fc68042 100644 --- a/addons/web_graph/static/src/js/pivot_table.js +++ b/addons/web_graph/static/src/js/pivot_table.js @@ -77,18 +77,20 @@ openerp.web_graph.PivotTable = openerp.web.Class.extend(openerp.EventDispatcherM var row_gbs = this.create_field_values(row_groupby), col_gbs = this.create_field_values(col_groupby), dom_changed = !_.isEqual(this.domain, domain), - gb_changed = !(_.isEqual(row_gbs, this.rows.groupby) && - _.isEqual(col_gbs, this.cols.groupby)); + row_gb_changed = !_.isEqual(row_gbs, this.rows.groupby), + col_gb_changed = !_.isEqual(col_gbs, this.cols.groupby); if (dom_changed) { this.domain = domain; } - if (gb_changed) { + if (row_gb_changed || col_gb_changed) { this.cols.groupby = col_gbs; this.rows.groupby = row_gbs; + if (row_gb_changed) {this.rows.headers = null; } + if (col_gb_changed) {this.cols.headers = null; } if (this.active) { this.trigger('groupby_changed'); } } - if (this.active && (gb_changed || dom_changed)) { + if (this.active && (row_gb_changed || col_gb_changed || dom_changed)) { this.update_data(); } }, -- cgit v1.2.3 From 4343ca278a21cd12880857736a9bf81a4cc83524 Mon Sep 17 00:00:00 2001 From: Gery Debongnie Date: Wed, 15 Jan 2014 11:51:04 +0100 Subject: [FIX] correctly compares groupby in pivot_table to avoid bugs/crashes (now, it ignores the 'interval' attributes) so the table can interact with the graph view (addon web_graph) bzr revid: ged@openerp.com-20140115105104-qff3t47lo1lyp5wd --- addons/web_graph/static/src/js/pivot_table.js | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) (limited to 'addons/web_graph/static/src/js/pivot_table.js') diff --git a/addons/web_graph/static/src/js/pivot_table.js b/addons/web_graph/static/src/js/pivot_table.js index edd1fc68042..79d351ce315 100644 --- a/addons/web_graph/static/src/js/pivot_table.js +++ b/addons/web_graph/static/src/js/pivot_table.js @@ -77,8 +77,8 @@ openerp.web_graph.PivotTable = openerp.web.Class.extend(openerp.EventDispatcherM var row_gbs = this.create_field_values(row_groupby), col_gbs = this.create_field_values(col_groupby), dom_changed = !_.isEqual(this.domain, domain), - row_gb_changed = !_.isEqual(row_gbs, this.rows.groupby), - col_gb_changed = !_.isEqual(col_gbs, this.cols.groupby); + row_gb_changed = !this.equal_groupby(row_gbs, this.rows.groupby), + col_gb_changed = !this.equal_groupby(col_gbs, this.cols.groupby); if (dom_changed) { this.domain = domain; @@ -95,6 +95,22 @@ openerp.web_graph.PivotTable = openerp.web.Class.extend(openerp.EventDispatcherM } }, + // compare groupby, ignoring the 'interval' attribute of dates... + // this is necessary to avoid problems with the groupby received by the + // context which do not have the interval attribute. This is ugly + // and need to be changed at some point + equal_groupby: function (groupby1, groupby2) { + if (groupby1.length !== groupby2.length) { return false; } + for (var i = 0; i < groupby1.length; i++) { + if (!this.equal_value(groupby1[i], groupby2[i])) { return false; } + } + return true; + }, + + equal_value: function (val1, val2) { + return ((val1.field === val2.field) && (val1.string === val2.string) && (val1.type === val2.type)); + }, + create_field_value: function (f) { if (f.field && f.interval) { return { field:f.field, -- cgit v1.2.3 From 588e5413872c5c50ba9f48d4fd094ae1ba05e3c7 Mon Sep 17 00:00:00 2001 From: Gery Debongnie Date: Thu, 16 Jan 2014 10:55:49 +0100 Subject: [FIX] fixes some issues with the col_group_bys in searchbar (main problem was that do_search is called twice when the user swap axis) (addon web_graph) bzr revid: ged@openerp.com-20140116095549-3f2hbyzj32nuj147 --- addons/web_graph/static/src/js/pivot_table.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'addons/web_graph/static/src/js/pivot_table.js') diff --git a/addons/web_graph/static/src/js/pivot_table.js b/addons/web_graph/static/src/js/pivot_table.js index 79d351ce315..d7a836d98b8 100644 --- a/addons/web_graph/static/src/js/pivot_table.js +++ b/addons/web_graph/static/src/js/pivot_table.js @@ -4,7 +4,7 @@ (function () { 'use strict'; -// Pivot Table emits the events 'groupby_changed' and 'redraw_required' when necessary. +// Pivot Table emits the events 'groupby_changed', 'groupby_swapped' and 'redraw_required' when necessary. // PivotTable is initialized by default 'inactive', and require a call to activate() // after init to load initial data and start triggering events. openerp.web_graph.PivotTable = openerp.web.Class.extend(openerp.EventDispatcherMixin, { @@ -318,7 +318,7 @@ openerp.web_graph.PivotTable = openerp.web.Class.extend(openerp.EventDispatcherM var temp = this.rows; this.rows = this.cols; this.cols = temp; - this.trigger('groupby_changed'); + this.trigger('groupby_swapped'); this.trigger('redraw_required'); }, -- cgit v1.2.3 From 6839fcaddd60d82c66626acfeaa7467232f67471 Mon Sep 17 00:00:00 2001 From: Gery Debongnie Date: Fri, 17 Jan 2014 11:23:39 +0100 Subject: [IMP] makes sure that the graph view does not reload data if the user removes a measure. Also, display the 'no data' screen if there are no current measure in graph view (addon web_graph) bzr revid: ged@openerp.com-20140117102339-99kka9v6wfsgesdn --- addons/web_graph/static/src/js/pivot_table.js | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) (limited to 'addons/web_graph/static/src/js/pivot_table.js') diff --git a/addons/web_graph/static/src/js/pivot_table.js b/addons/web_graph/static/src/js/pivot_table.js index d7a836d98b8..61a6587e0a2 100644 --- a/addons/web_graph/static/src/js/pivot_table.js +++ b/addons/web_graph/static/src/js/pivot_table.js @@ -61,16 +61,25 @@ openerp.web_graph.PivotTable = openerp.web.Class.extend(openerp.EventDispatcherM toggle_measure: function (field_id) { var current_measure = _.findWhere(this.measures, {field:field_id}); - if (current_measure) { + if (current_measure) { // remove current_measure + var index = this.measures.indexOf(current_measure); this.measures = _.without(this.measures, current_measure); - } else { + if (this.measures.length === 0) { + this.nodata = true; + } else { + _.each(this.cells, function (cell) { + cell.values.splice(index, 1); + }); + } + if (this.active) { this.trigger('redraw_required'); } + } else { // add a new measure this.measures.push({ field: field_id, type: this.fields[field_id].type, string: this.fields[field_id].string }); + if (this.active) { this.update_data(); } } - if (this.active) { this.update_data(); } }, set: function (domain, row_groupby, col_groupby) { @@ -401,6 +410,12 @@ openerp.web_graph.PivotTable = openerp.web.Class.extend(openerp.EventDispatcherM rows = this.rows.groupby, visible_fields = rows.concat(cols, self.measures); + if (this.measures.length === 0) { + var result = $.Deferred(); + result.resolve() + return result; + } + var groupbys = _.map(_.range(cols.length + 1), function (i) { return cols.slice(0, i).concat(rows); }); -- cgit v1.2.3 From c54746744251924691a9aa1170d32f3bc1c4d50d Mon Sep 17 00:00:00 2001 From: Gery Debongnie Date: Fri, 17 Jan 2014 15:43:03 +0100 Subject: [IMP] adds checkmarks next to measures when they are used in graph view (addon web_graph) bzr revid: ged@openerp.com-20140117144303-tqj7cn5xd1c0xvhm --- addons/web_graph/static/src/js/pivot_table.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'addons/web_graph/static/src/js/pivot_table.js') diff --git a/addons/web_graph/static/src/js/pivot_table.js b/addons/web_graph/static/src/js/pivot_table.js index 61a6587e0a2..55719200098 100644 --- a/addons/web_graph/static/src/js/pivot_table.js +++ b/addons/web_graph/static/src/js/pivot_table.js @@ -17,7 +17,7 @@ openerp.web_graph.PivotTable = openerp.web.Class.extend(openerp.EventDispatcherM this.model = model; this.fields = fields; this.fields.__count = {type: 'integer', string:'Quantity'}; - this.measures = [{field:'__count', type: this.fields.type, string:this.fields.string}]; + this.measures = [{field:'__count', type: 'integer', string:'Quantity'}]; this.active = false; this.rows = { groupby: this.create_field_values(options.row_groupby || []), headers: null }; this.cols = { groupby: this.create_field_values(options.col_groupby || []), headers: null }; @@ -410,10 +410,10 @@ openerp.web_graph.PivotTable = openerp.web.Class.extend(openerp.EventDispatcherM rows = this.rows.groupby, visible_fields = rows.concat(cols, self.measures); - if (this.measures.length === 0) { + if (this.measures.length === 0) { var result = $.Deferred(); - result.resolve() - return result; + result.resolve(); + return result; } var groupbys = _.map(_.range(cols.length + 1), function (i) { -- cgit v1.2.3 From 5aade330c20a1021eaa31bf932dab81dd45ec431 Mon Sep 17 00:00:00 2001 From: Gery Debongnie Date: Fri, 17 Jan 2014 16:33:30 +0100 Subject: [FIX] fixes a typo (nodata => no_data), which prevents a crash in graph_view, addon web_graph) bzr revid: ged@openerp.com-20140117153330-9vc6bzljmso9zu71 --- addons/web_graph/static/src/js/pivot_table.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'addons/web_graph/static/src/js/pivot_table.js') diff --git a/addons/web_graph/static/src/js/pivot_table.js b/addons/web_graph/static/src/js/pivot_table.js index 55719200098..476891644d7 100644 --- a/addons/web_graph/static/src/js/pivot_table.js +++ b/addons/web_graph/static/src/js/pivot_table.js @@ -65,7 +65,7 @@ openerp.web_graph.PivotTable = openerp.web.Class.extend(openerp.EventDispatcherM var index = this.measures.indexOf(current_measure); this.measures = _.without(this.measures, current_measure); if (this.measures.length === 0) { - this.nodata = true; + this.no_data = true; } else { _.each(this.cells, function (cell) { cell.values.splice(index, 1); -- cgit v1.2.3 From ba9999c28aa0e821924e5792a672eb429467ab6c Mon Sep 17 00:00:00 2001 From: Gery Debongnie Date: Fri, 17 Jan 2014 17:19:40 +0100 Subject: [FIX] fix crash happening when user goes to graph view, switch to other view, changes groupby and goes back to graph view. (addon web_graph) bzr revid: ged@openerp.com-20140117161940-3ojz17luxtsb9qfa --- addons/web_graph/static/src/js/pivot_table.js | 1 + 1 file changed, 1 insertion(+) (limited to 'addons/web_graph/static/src/js/pivot_table.js') diff --git a/addons/web_graph/static/src/js/pivot_table.js b/addons/web_graph/static/src/js/pivot_table.js index 476891644d7..26c1395dff6 100644 --- a/addons/web_graph/static/src/js/pivot_table.js +++ b/addons/web_graph/static/src/js/pivot_table.js @@ -82,6 +82,7 @@ openerp.web_graph.PivotTable = openerp.web.Class.extend(openerp.EventDispatcherM } }, + // return true if an update is triggered, false otherwise set: function (domain, row_groupby, col_groupby) { var row_gbs = this.create_field_values(row_groupby), col_gbs = this.create_field_values(col_groupby), -- cgit v1.2.3 From f404bf8b406ef276f4c16856172ef1ecd2f45dae Mon Sep 17 00:00:00 2001 From: Gery Debongnie Date: Mon, 20 Jan 2014 10:32:54 +0100 Subject: [IMP] optimizes pivot table so that it doesn't reload data when the groupbys have been changed in such a way that it should only fold some headers (addon web_graph) bzr revid: ged@openerp.com-20140120093254-mta9v6hjmsgfpr2n --- addons/web_graph/static/src/js/pivot_table.js | 54 ++++++++++++++++++++++----- 1 file changed, 45 insertions(+), 9 deletions(-) (limited to 'addons/web_graph/static/src/js/pivot_table.js') diff --git a/addons/web_graph/static/src/js/pivot_table.js b/addons/web_graph/static/src/js/pivot_table.js index 26c1395dff6..d54161f8ba7 100644 --- a/addons/web_graph/static/src/js/pivot_table.js +++ b/addons/web_graph/static/src/js/pivot_table.js @@ -87,12 +87,27 @@ openerp.web_graph.PivotTable = openerp.web.Class.extend(openerp.EventDispatcherM var row_gbs = this.create_field_values(row_groupby), col_gbs = this.create_field_values(col_groupby), dom_changed = !_.isEqual(this.domain, domain), + row_subset = is_strict_beginning_of(row_gbs, this.rows.groupby), + col_subset = is_strict_beginning_of(col_gbs, this.cols.groupby), row_gb_changed = !this.equal_groupby(row_gbs, this.rows.groupby), col_gb_changed = !this.equal_groupby(col_gbs, this.cols.groupby); if (dom_changed) { this.domain = domain; } + + if (row_subset && !dom_changed && !col_gb_changed) { + this.fold_with_depth(this.rows, row_gbs.length); + if (this.active) { this.trigger('redraw_required'); } + return; + } + + if (col_subset && !dom_changed && !row_gb_changed) { + this.fold_with_depth(this.cols, col_gbs.length); + if (this.active) { this.trigger('redraw_required'); } + return; + } + if (row_gb_changed || col_gb_changed) { this.cols.groupby = col_gbs; this.rows.groupby = row_gbs; @@ -193,18 +208,20 @@ openerp.web_graph.PivotTable = openerp.web.Class.extend(openerp.EventDispatcherM }); }, + _get_headers_with_depth: function (headers, depth) { + return _.filter(headers, function (header) { + return header.path.length === depth; + }); + }, + // return all columns with a path length of 'depth' get_cols_with_depth: function (depth) { - return _.filter(this.cols.headers, function (header) { - return header.path.length === depth; - }); + return this._get_headers_with_depth(this.cols.headers, depth); }, // return all rows with a path length of 'depth' get_rows_with_depth: function (depth) { - return _.filter(this.rows.headers, function (header) { - return header.path.length === depth; - }); + return this._get_headers_with_depth(this.rows.headers), depth; }, // return all non expanded rows @@ -250,7 +267,7 @@ openerp.web_graph.PivotTable = openerp.web.Class.extend(openerp.EventDispatcherM // ---------------------------------------------------------------------- // Table manipulation methods : fold/expand/swap // ---------------------------------------------------------------------- - fold: function (header) { + fold: function (header, silent) { var ancestors = this.get_ancestors(header), removed_ids = _.pluck(ancestors, 'id'); @@ -265,11 +282,18 @@ openerp.web_graph.PivotTable = openerp.web.Class.extend(openerp.EventDispatcherM var new_groupby_length = _.max(_.map(header.root.headers, function(g) {return g.path.length;})); if (new_groupby_length < header.root.groupby.length) { header.root.groupby.splice(new_groupby_length); - this.trigger('groupby_changed'); + if (!silent) { this.trigger('groupby_changed'); } } - this.trigger('redraw_required'); + if (!silent) { this.trigger('redraw_required'); } }, + fold_with_depth: function (root, depth) { + var self = this; + _.each(this._get_headers_with_depth(root.headers, depth), function (header) { + self.fold(header, true); + }); + }, + expand: function (header_id, groupby) { var self = this, header = this.get_header(header_id), @@ -568,6 +592,18 @@ openerp.web_graph.PivotTable = openerp.web.Class.extend(openerp.EventDispatcherM }, }); + +// Utility function: returns true if the beginning of array2 is array1 and +// if array1 is not array2 +function is_strict_beginning_of (array1, array2) { + if (array1.length >= array2.length) { return false; } + var result = true; + for (var i = 0; i < array1.length; i++) { + if (!_.isEqual(array1[i], array2[i])) { return false;} + } + return result; +} + })(); -- cgit v1.2.3 From 2cafcfbde7612c1d16513ad7ddc416de7d6a6497 Mon Sep 17 00:00:00 2001 From: Gery Debongnie Date: Tue, 21 Jan 2014 15:30:34 +0100 Subject: [REF] large refactoring in graph view: changes the flow of the program to make it much simpler (addon web_graph) bzr revid: ged@openerp.com-20140121143034-rid4saax5y63g7i1 --- addons/web_graph/static/src/js/pivot_table.js | 203 ++++++-------------------- 1 file changed, 42 insertions(+), 161 deletions(-) (limited to 'addons/web_graph/static/src/js/pivot_table.js') diff --git a/addons/web_graph/static/src/js/pivot_table.js b/addons/web_graph/static/src/js/pivot_table.js index d54161f8ba7..74197f3a984 100644 --- a/addons/web_graph/static/src/js/pivot_table.js +++ b/addons/web_graph/static/src/js/pivot_table.js @@ -4,10 +4,8 @@ (function () { 'use strict'; -// Pivot Table emits the events 'groupby_changed', 'groupby_swapped' and 'redraw_required' when necessary. -// PivotTable is initialized by default 'inactive', and require a call to activate() -// after init to load initial data and start triggering events. -openerp.web_graph.PivotTable = openerp.web.Class.extend(openerp.EventDispatcherMixin, { +// PivotTable requires a call to update_data after initialization +openerp.web_graph.PivotTable = openerp.web.Class.extend({ init: function (model, domain, fields, options) { openerp.EventDispatcherMixin.init.call(this); @@ -17,11 +15,9 @@ openerp.web_graph.PivotTable = openerp.web.Class.extend(openerp.EventDispatcherM this.model = model; this.fields = fields; this.fields.__count = {type: 'integer', string:'Quantity'}; - this.measures = [{field:'__count', type: 'integer', string:'Quantity'}]; - this.active = false; - this.rows = { groupby: this.create_field_values(options.row_groupby || []), headers: null }; - this.cols = { groupby: this.create_field_values(options.col_groupby || []), headers: null }; - if (options.measures) { this.set_measures(options.measures); } + this.measures = options.measures || []; + this.rows = { groupby: options.row_groupby, headers: null }; + this.cols = { groupby: options.col_groupby, headers: null }; }, // ---------------------------------------------------------------------- @@ -31,36 +27,13 @@ openerp.web_graph.PivotTable = openerp.web.Class.extend(openerp.EventDispatcherM // this.rows.groupby, this.cols.groupby : list of groupbys used for describing rows (...), // a groupby is also {field:_, string:_, type:_} but it also has a interval // attribute if its type is date/datetime. - // this.active: If PivotTable is active then it triggers events and updates - // its values when necessary - activate: function() { - this.active = true; - this.update_data(); - }, - set_measures: function (measures) { - var self = this; - if (!_.isEqual(measures, this.measures)) { - this.measures = []; - _.each(measures, function (m) { self._add_measure(m); }); - if (this.active) { this.update_data(); } - } - }, - - _add_measure: function (measure) { - if (measure.field && measure.string && measure.type) { - this.measures.push(measure); - } else { - this.measures.push({ - field: measure, - string: this.fields[measure].string, - type: this.fields[measure].type, - }); - } + this.measures = measures; + return this.update_data(); }, - toggle_measure: function (field_id) { - var current_measure = _.findWhere(this.measures, {field:field_id}); + toggle_measure: function (measure) { + var current_measure = _.findWhere(this.measures, measure); if (current_measure) { // remove current_measure var index = this.measures.indexOf(current_measure); this.measures = _.without(this.measures, current_measure); @@ -71,92 +44,27 @@ openerp.web_graph.PivotTable = openerp.web.Class.extend(openerp.EventDispatcherM cell.values.splice(index, 1); }); } - if (this.active) { this.trigger('redraw_required'); } + return $.Deferred().resolve(); } else { // add a new measure - this.measures.push({ - field: field_id, - type: this.fields[field_id].type, - string: this.fields[field_id].string - }); - if (this.active) { this.update_data(); } + this.measures.push(measure); + return this.update_data(); } }, - // return true if an update is triggered, false otherwise set: function (domain, row_groupby, col_groupby) { - var row_gbs = this.create_field_values(row_groupby), - col_gbs = this.create_field_values(col_groupby), - dom_changed = !_.isEqual(this.domain, domain), - row_subset = is_strict_beginning_of(row_gbs, this.rows.groupby), - col_subset = is_strict_beginning_of(col_gbs, this.cols.groupby), - row_gb_changed = !this.equal_groupby(row_gbs, this.rows.groupby), - col_gb_changed = !this.equal_groupby(col_gbs, this.cols.groupby); - - if (dom_changed) { - this.domain = domain; - } - - if (row_subset && !dom_changed && !col_gb_changed) { - this.fold_with_depth(this.rows, row_gbs.length); - if (this.active) { this.trigger('redraw_required'); } - return; - } - - if (col_subset && !dom_changed && !row_gb_changed) { - this.fold_with_depth(this.cols, col_gbs.length); - if (this.active) { this.trigger('redraw_required'); } - return; - } - - if (row_gb_changed || col_gb_changed) { - this.cols.groupby = col_gbs; - this.rows.groupby = row_gbs; - if (row_gb_changed) {this.rows.headers = null; } - if (col_gb_changed) {this.cols.headers = null; } - if (this.active) { this.trigger('groupby_changed'); } - } - if (this.active && (row_gb_changed || col_gb_changed || dom_changed)) { - this.update_data(); - } - }, - - // compare groupby, ignoring the 'interval' attribute of dates... - // this is necessary to avoid problems with the groupby received by the - // context which do not have the interval attribute. This is ugly - // and need to be changed at some point - equal_groupby: function (groupby1, groupby2) { - if (groupby1.length !== groupby2.length) { return false; } - for (var i = 0; i < groupby1.length; i++) { - if (!this.equal_value(groupby1[i], groupby2[i])) { return false; } - } - return true; - }, - - equal_value: function (val1, val2) { - return ((val1.field === val2.field) && (val1.string === val2.string) && (val1.type === val2.type)); - }, + var row_gb_changed = !_.isEqual(row_groupby, this.rows.groupby), + col_gb_changed = !_.isEqual(col_groupby, this.cols.groupby); + + this.domain = domain; + this.rows.groupby = row_groupby; + this.cols.groupby = col_groupby; - create_field_value: function (f) { - if (f.field && f.interval) { - return { field:f.field, - string: this.fields[f.field].string, - type:this.fields[f.field].type, - interval: f.interval }; - } - return (f.field && f.string && f.type) ? f : { field: f, - string: this.fields[f].string, - type: this.fields[f].type }; - }, + if (row_gb_changed) { this.rows.headers = null; } + if (col_gb_changed) { this.cols.headers = null; } - create_field_values: function (field_ids) { - var self = this; - return _.map(field_ids, function (f) { return self.create_field_value(f); }); + return this.update_data(); }, - _add_groupby: function(groupby_list, groupby) { - groupby_list.push(this.create_field_value(groupby)); - }, - // ---------------------------------------------------------------------- // Cells manipulation methods // ---------------------------------------------------------------------- @@ -191,21 +99,15 @@ openerp.web_graph.PivotTable = openerp.web.Class.extend(openerp.EventDispatcherM // expanded:_ (boolean, true if it has been expanded) // } is_row: function (id) { - return !!_.find(this.rows.headers, function (header) { - return header.id === id; - }); - }, + return !!_.findWhere(this.rows.headers, {id:id}); + }, is_col: function (id) { - return !!_.find(this.cols.headers, function (header) { - return header.id === id; - }); + return !!_.findWhere(this.cols.headers, {id:id}); }, get_header: function (id) { - return _.find(this.rows.headers.concat(this.cols.headers), function (header) { - return header.id === id; - }); + return _.findWhere(this.rows.headers.concat(this.cols.headers), {id:id}); }, _get_headers_with_depth: function (headers, depth) { @@ -221,21 +123,17 @@ openerp.web_graph.PivotTable = openerp.web.Class.extend(openerp.EventDispatcherM // return all rows with a path length of 'depth' get_rows_with_depth: function (depth) { - return this._get_headers_with_depth(this.rows.headers), depth; + return this._get_headers_with_depth(this.rows.headers, depth); }, // return all non expanded rows get_rows_leaves: function () { - return _.filter(this.rows.headers, function (header) { - return !header.expanded; - }); + return _.where(this.rows.headers, {expanded:false}); }, // return all non expanded cols get_cols_leaves: function () { - return _.filter(this.cols.headers, function (header) { - return !header.expanded; - }); + return _.where(this.cols.headers, {expanded:false}); }, get_ancestors: function (header) { @@ -267,7 +165,8 @@ openerp.web_graph.PivotTable = openerp.web.Class.extend(openerp.EventDispatcherM // ---------------------------------------------------------------------- // Table manipulation methods : fold/expand/swap // ---------------------------------------------------------------------- - fold: function (header, silent) { + // return true if the folding changed the groupbys, false if not + fold: function (header) { var ancestors = this.get_ancestors(header), removed_ids = _.pluck(ancestors, 'id'); @@ -279,12 +178,12 @@ openerp.web_graph.PivotTable = openerp.web.Class.extend(openerp.EventDispatcherM return (_.contains(removed_ids, cell.x) || _.contains(removed_ids, cell.y)); }); - var new_groupby_length = _.max(_.map(header.root.headers, function(g) {return g.path.length;})); + var new_groupby_length = _.max(_.pluck(_.pluck(header.root.headers, 'path'), 'length')); if (new_groupby_length < header.root.groupby.length) { header.root.groupby.splice(new_groupby_length); - if (!silent) { this.trigger('groupby_changed'); } + return true; } - if (!silent) { this.trigger('redraw_required'); } + return false; }, fold_with_depth: function (root, depth) { @@ -294,6 +193,12 @@ openerp.web_graph.PivotTable = openerp.web.Class.extend(openerp.EventDispatcherM }); }, + expand_all: function () { + this.rows.headers = null; + this.cols.headers = null; + return this.update_data(); + }, + expand: function (header_id, groupby) { var self = this, header = this.get_header(header_id), @@ -301,10 +206,9 @@ openerp.web_graph.PivotTable = openerp.web.Class.extend(openerp.EventDispatcherM fields = otherRoot.groupby.concat(this.measures); if (header.path.length === header.root.groupby.length) { - self._add_groupby(header.root.groupby, groupby); - this.trigger('groupby_changed'); + header.root.groupby.push(groupby); } - groupby = [header.root.groupby[header.path.length]].concat(otherRoot.groupby); + groupby = [groupby].concat(otherRoot.groupby); return this.get_groups(groupby, fields, header.domain) .then(function (groups) { @@ -332,7 +236,6 @@ openerp.web_graph.PivotTable = openerp.web.Class.extend(openerp.EventDispatcherM }); }); header.expanded = true; - self.trigger('redraw_required'); }); }, @@ -352,8 +255,6 @@ openerp.web_graph.PivotTable = openerp.web.Class.extend(openerp.EventDispatcherM var temp = this.rows; this.rows = this.cols; this.cols = temp; - this.trigger('groupby_swapped'); - this.trigger('redraw_required'); }, // ---------------------------------------------------------------------- @@ -374,7 +275,6 @@ openerp.web_graph.PivotTable = openerp.web.Class.extend(openerp.EventDispatcherM } else { self.no_data = true; } - self.trigger('redraw_required'); }); }, @@ -413,12 +313,6 @@ openerp.web_graph.PivotTable = openerp.web.Class.extend(openerp.EventDispatcherM root.headers = updated_headers; }, - expand_all: function () { - this.rows.headers = null; - this.cols.headers = null; - this.update_data(); - }, - // ---------------------------------------------------------------------- // Data loading methods // ---------------------------------------------------------------------- @@ -436,9 +330,7 @@ openerp.web_graph.PivotTable = openerp.web.Class.extend(openerp.EventDispatcherM visible_fields = rows.concat(cols, self.measures); if (this.measures.length === 0) { - var result = $.Deferred(); - result.resolve(); - return result; + return $.Deferred.resolve().promise(); } var groupbys = _.map(_.range(cols.length + 1), function (i) { @@ -593,17 +485,6 @@ openerp.web_graph.PivotTable = openerp.web.Class.extend(openerp.EventDispatcherM }); -// Utility function: returns true if the beginning of array2 is array1 and -// if array1 is not array2 -function is_strict_beginning_of (array1, array2) { - if (array1.length >= array2.length) { return false; } - var result = true; - for (var i = 0; i < array1.length; i++) { - if (!_.isEqual(array1[i], array2[i])) { return false;} - } - return result; -} - })(); -- cgit v1.2.3 From d1e3504b8051a91ea85f5add314277caef6592d9 Mon Sep 17 00:00:00 2001 From: Gery Debongnie Date: Wed, 22 Jan 2014 08:56:52 +0100 Subject: [IMP] two small tweaks to improve the code quality in addon web_graph bzr revid: ged@openerp.com-20140122075652-wz2uk3tv31ady4ej --- addons/web_graph/static/src/js/pivot_table.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'addons/web_graph/static/src/js/pivot_table.js') diff --git a/addons/web_graph/static/src/js/pivot_table.js b/addons/web_graph/static/src/js/pivot_table.js index 74197f3a984..5a2e93ecd7c 100644 --- a/addons/web_graph/static/src/js/pivot_table.js +++ b/addons/web_graph/static/src/js/pivot_table.js @@ -423,7 +423,7 @@ openerp.web_graph.PivotTable = openerp.web.Class.extend({ if (group.attributes.grouped_on && this.fields[group.attributes.grouped_on].type === 'selection') { var selection = this.fields[group.attributes.grouped_on].selection, - value_lookup = _.find(selection, function (val) { return val[0] === value; }); + value_lookup = _.where(selection, {0:value}); group.attributes.value = value_lookup ? value_lookup[1] : 'undefined'; } else if (value === false) { group.attributes.value = 'undefined'; -- cgit v1.2.3 From a3bb723379d5b9c9302658925c076ce4a341d76c Mon Sep 17 00:00:00 2001 From: Gery Debongnie Date: Wed, 22 Jan 2014 14:34:52 +0100 Subject: [IMP] changes the backend code of graph view to use the new functionality of read_group (use 'field_name:interval' in readgroup instead of context (addon web_graph) bzr revid: ged@openerp.com-20140122133452-wy3hrsrokhnwc3ru --- addons/web_graph/static/src/js/pivot_table.js | 78 +++++++++++---------------- 1 file changed, 32 insertions(+), 46 deletions(-) (limited to 'addons/web_graph/static/src/js/pivot_table.js') diff --git a/addons/web_graph/static/src/js/pivot_table.js b/addons/web_graph/static/src/js/pivot_table.js index 5a2e93ecd7c..17a70d22c26 100644 --- a/addons/web_graph/static/src/js/pivot_table.js +++ b/addons/web_graph/static/src/js/pivot_table.js @@ -221,6 +221,7 @@ openerp.web_graph.PivotTable = openerp.web.Class.extend({ // make cells _.each(self.get_ancestors_and_self(group), function (data) { var values = _.map(self.measures, function (m) { + console.log('m.field', m.field); return data.attributes.aggregates[m.field]; }); var other = _.find(otherRoot.headers, function (h) { @@ -230,6 +231,8 @@ openerp.web_graph.PivotTable = openerp.web.Class.extend({ return _.isEqual(_.rest(data.path), h.path); } }); + console.log('dbg', child.id, other.id, values); + if (_.isEqual(values, [46125])) debugger; if (other) { self.add_cell(child.id, other.id, values); } @@ -378,37 +381,14 @@ openerp.web_graph.PivotTable = openerp.web.Class.extend({ _query_db: function (groupby, fields, domain, path) { var self = this, field_ids = _.without(_.pluck(fields, 'field'), '__count'), - context = {}; - - if (groupby.interval) { - context.datetime_format = {}; - var display_format; - switch (groupby.interval) { - case 'day': - display_format = 'dd MMMM YYYY'; - break; - case 'week': - display_format = 'w YYYY'; - break; - case 'month': - display_format = 'MMMM YYYY'; - break; - case 'quarter': - display_format = 'QQQ YYYY'; - break; - case 'year': - display_format = 'YYYY'; - break; - } - context.datetime_format[groupby.field] = { - interval: groupby.interval, - display_format: display_format - }; - } + formatted_groupby = (groupby.interval) ? groupby.field + ':' + groupby.interval : groupby.field; + + fields = _.map(field_ids, function (field) { + return (_.contains(field, ':')) ? field.split(':')[0] : field; + }); return this.model.query(field_ids) .filter(domain) - .context(context) - .group_by(groupby.field) + .group_by(formatted_groupby) .then(function (results) { var groups = _.filter(results, function (group) { return group.attributes.length > 0; @@ -417,25 +397,32 @@ openerp.web_graph.PivotTable = openerp.web.Class.extend({ }); }, + // if field is a fieldname, returns field, if field is field_id:interval, retuns field_id + raw_field: function (field) { + return (_.contains(field, ':')) ? field.split(':')[0] : field; + }, + // add the path to the group and sanitize the value... - format_group: function (group, current_path) { - var value = group.attributes.value; - - if (group.attributes.grouped_on && this.fields[group.attributes.grouped_on].type === 'selection') { - var selection = this.fields[group.attributes.grouped_on].selection, - value_lookup = _.where(selection, {0:value}); - group.attributes.value = value_lookup ? value_lookup[1] : 'undefined'; - } else if (value === false) { - group.attributes.value = 'undefined'; - } else if (value instanceof Array) { - group.attributes.value = value[1]; - } - - group.path = value ? (current_path || []).concat(group.attributes.value) : []; + format_group: function (group, current_path) { + var attrs = group.attributes, + value = attrs.value, + grouped_on = attrs.grouped_on ? this.raw_field(attrs.grouped_on) : false; + + if (grouped_on && this.fields[grouped_on].type === 'selection') { + var selection = this.fields[grouped_on].selection, + value_lookup = _.where(selection, {0:value}); + group.attributes.value = value_lookup ? value_lookup[1] : 'undefined'; + } else if (value === false) { + group.attributes.value = 'undefined'; + } else if (value instanceof Array) { + group.attributes.value = value[1]; + } + + group.path = (value !== undefined) ? (current_path || []).concat(group.attributes.value) : []; group.attributes.aggregates.__count = group.attributes.length; - return group; - }, + return group; + }, format_data: function (total, col_data, row_data, cell_data) { var self = this, @@ -476,7 +463,6 @@ openerp.web_graph.PivotTable = openerp.web.Class.extend({ var row = _.find(rows, function (header) { return _.isEqual(header.path, path.slice(index)); }); var col = _.find(cols, function (header) { return _.isEqual(header.path, path.slice(0, index)); }); self.add_cell(row.id, col.id, values); - if (group.children) { self.make_cells (group.children, index, path, rows, cols); } -- cgit v1.2.3 From 39e0f4736f447fe5e4160e670a74e0b79a5ad266 Mon Sep 17 00:00:00 2001 From: Gery Debongnie Date: Wed, 22 Jan 2014 17:07:07 +0100 Subject: [REF] refactoring: removes the 'interval' attributes in groupbys and improves searchbar integration (addon web_graph) bzr revid: ged@openerp.com-20140122160707-39el7frwfj4pwd4d --- addons/web_graph/static/src/js/pivot_table.js | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) (limited to 'addons/web_graph/static/src/js/pivot_table.js') diff --git a/addons/web_graph/static/src/js/pivot_table.js b/addons/web_graph/static/src/js/pivot_table.js index 17a70d22c26..38662b01167 100644 --- a/addons/web_graph/static/src/js/pivot_table.js +++ b/addons/web_graph/static/src/js/pivot_table.js @@ -25,8 +25,9 @@ openerp.web_graph.PivotTable = openerp.web.Class.extend({ // ---------------------------------------------------------------------- // this.measures: list of measure [measure], measure = {field: _, string: _, type: _} // this.rows.groupby, this.cols.groupby : list of groupbys used for describing rows (...), - // a groupby is also {field:_, string:_, type:_} but it also has a interval - // attribute if its type is date/datetime. + // a groupby is also {field:_, string:_, type:_} + // If its type is date/datetime, field can have the corresponding interval in its description, + // for example 'create_date:week'. set_measures: function (measures) { this.measures = measures; return this.update_data(); @@ -221,7 +222,6 @@ openerp.web_graph.PivotTable = openerp.web.Class.extend({ // make cells _.each(self.get_ancestors_and_self(group), function (data) { var values = _.map(self.measures, function (m) { - console.log('m.field', m.field); return data.attributes.aggregates[m.field]; }); var other = _.find(otherRoot.headers, function (h) { @@ -231,8 +231,6 @@ openerp.web_graph.PivotTable = openerp.web.Class.extend({ return _.isEqual(_.rest(data.path), h.path); } }); - console.log('dbg', child.id, other.id, values); - if (_.isEqual(values, [46125])) debugger; if (other) { self.add_cell(child.id, other.id, values); } @@ -381,14 +379,11 @@ openerp.web_graph.PivotTable = openerp.web.Class.extend({ _query_db: function (groupby, fields, domain, path) { var self = this, field_ids = _.without(_.pluck(fields, 'field'), '__count'), - formatted_groupby = (groupby.interval) ? groupby.field + ':' + groupby.interval : groupby.field; + fields = _.map(field_ids, function(f) { return self.raw_field(f); }); - fields = _.map(field_ids, function (field) { - return (_.contains(field, ':')) ? field.split(':')[0] : field; - }); return this.model.query(field_ids) .filter(domain) - .group_by(formatted_groupby) + .group_by(groupby.field) .then(function (results) { var groups = _.filter(results, function (group) { return group.attributes.length > 0; -- cgit v1.2.3 From 59b75a0176143da2756e8658ea853a64b23e7e84 Mon Sep 17 00:00:00 2001 From: Gery Debongnie Date: Thu, 23 Jan 2014 15:23:18 +0100 Subject: [FIX] fixes a problem with fields selection : the string was not correctly displayed (addon web_graph) bzr revid: ged@openerp.com-20140123142318-kbk6f2rsug3uxi0j --- addons/web_graph/static/src/js/pivot_table.js | 49 +++++++++++++-------------- 1 file changed, 24 insertions(+), 25 deletions(-) (limited to 'addons/web_graph/static/src/js/pivot_table.js') diff --git a/addons/web_graph/static/src/js/pivot_table.js b/addons/web_graph/static/src/js/pivot_table.js index 38662b01167..f47fcabc92e 100644 --- a/addons/web_graph/static/src/js/pivot_table.js +++ b/addons/web_graph/static/src/js/pivot_table.js @@ -211,33 +211,32 @@ openerp.web_graph.PivotTable = openerp.web.Class.extend({ } groupby = [groupby].concat(otherRoot.groupby); - return this.get_groups(groupby, fields, header.domain) - .then(function (groups) { - _.each(groups.reverse(), function (group) { - // make header - var child = self.make_header(group, header); - child.expanded = false; - header.children.splice(0,0, child); - header.root.headers.splice(header.root.headers.indexOf(header) + 1, 0, child); - // make cells - _.each(self.get_ancestors_and_self(group), function (data) { - var values = _.map(self.measures, function (m) { - return data.attributes.aggregates[m.field]; - }); - var other = _.find(otherRoot.headers, function (h) { - if (header.root === self.cols) { - return _.isEqual(data.path.slice(1), h.path); - } else { - return _.isEqual(_.rest(data.path), h.path); - } - }); - if (other) { - self.add_cell(child.id, other.id, values); - } + return this.get_groups(groupby, fields, header.domain).then(function (groups) { + _.each(groups.reverse(), function (group) { + // make header + var child = self.make_header(group, header); + child.expanded = false; + header.children.splice(0,0, child); + header.root.headers.splice(header.root.headers.indexOf(header) + 1, 0, child); + // make cells + _.each(self.get_ancestors_and_self(group), function (data) { + var values = _.map(self.measures, function (m) { + return data.attributes.aggregates[m.field]; }); + var other = _.find(otherRoot.headers, function (h) { + if (header.root === self.cols) { + return _.isEqual(data.path.slice(1), h.path); + } else { + return _.isEqual(_.rest(data.path), h.path); + } + }); + if (other) { + self.add_cell(child.id, other.id, values); + } }); - header.expanded = true; }); + header.expanded = true; + }); }, make_header: function (group, parent) { @@ -406,7 +405,7 @@ openerp.web_graph.PivotTable = openerp.web.Class.extend({ if (grouped_on && this.fields[grouped_on].type === 'selection') { var selection = this.fields[grouped_on].selection, value_lookup = _.where(selection, {0:value}); - group.attributes.value = value_lookup ? value_lookup[1] : 'undefined'; + group.attributes.value = value_lookup ? value_lookup[0][1] : 'undefined'; } else if (value === false) { group.attributes.value = 'undefined'; } else if (value instanceof Array) { -- cgit v1.2.3 From 524324ae4e4ec21b58d2d3a89340d1d36173b260 Mon Sep 17 00:00:00 2001 From: Gery Debongnie Date: Fri, 24 Jan 2014 13:59:44 +0100 Subject: [FIX] fixes two small issues concerning the groupby dates in graph view (addon web_graph) bzr revid: ged@openerp.com-20140124125944-wxl4zdya37pxdnqv --- addons/web_graph/static/src/js/pivot_table.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'addons/web_graph/static/src/js/pivot_table.js') diff --git a/addons/web_graph/static/src/js/pivot_table.js b/addons/web_graph/static/src/js/pivot_table.js index f47fcabc92e..d5c01765504 100644 --- a/addons/web_graph/static/src/js/pivot_table.js +++ b/addons/web_graph/static/src/js/pivot_table.js @@ -402,12 +402,12 @@ openerp.web_graph.PivotTable = openerp.web.Class.extend({ value = attrs.value, grouped_on = attrs.grouped_on ? this.raw_field(attrs.grouped_on) : false; - if (grouped_on && this.fields[grouped_on].type === 'selection') { + if (value === false) { + group.attributes.value = 'undefined'; + } else if (grouped_on && this.fields[grouped_on].type === 'selection') { var selection = this.fields[grouped_on].selection, value_lookup = _.where(selection, {0:value}); group.attributes.value = value_lookup ? value_lookup[0][1] : 'undefined'; - } else if (value === false) { - group.attributes.value = 'undefined'; } else if (value instanceof Array) { group.attributes.value = value[1]; } -- cgit v1.2.3 From c43147628b6cfe9eb62b0da797cdff3f2c53d443 Mon Sep 17 00:00:00 2001 From: Gery Debongnie Date: Fri, 24 Jan 2014 16:16:35 +0100 Subject: [REF] lots of small tweaks to improve the code, and some small fixes, after xmo's code review (addon web_graph) bzr revid: ged@openerp.com-20140124151635-14l3dchnrmujo5ni --- addons/web_graph/static/src/js/pivot_table.js | 36 +++++++++++---------------- 1 file changed, 14 insertions(+), 22 deletions(-) (limited to 'addons/web_graph/static/src/js/pivot_table.js') diff --git a/addons/web_graph/static/src/js/pivot_table.js b/addons/web_graph/static/src/js/pivot_table.js index d5c01765504..a5bfba3c09a 100644 --- a/addons/web_graph/static/src/js/pivot_table.js +++ b/addons/web_graph/static/src/js/pivot_table.js @@ -8,7 +8,6 @@ openerp.web_graph.PivotTable = openerp.web.Class.extend({ init: function (model, domain, fields, options) { - openerp.EventDispatcherMixin.init.call(this); this.cells = []; this.domain = domain; this.no_data = true; @@ -79,9 +78,7 @@ openerp.web_graph.PivotTable = openerp.web.Class.extend({ }, get_values: function (id1, id2, default_values) { - var cell = _.find(this.cells, function (c) { - return ((c.x == Math.min(id1, id2)) && (c.y == Math.max(id1, id2))); - }); + var cell = _.findWhere(this.cells, {x: Math.min(id1, id2), y: Math.max(id1, id2)}); return (cell !== undefined) ? cell.values : (default_values || new Array(this.measures.length)); }, @@ -149,10 +146,8 @@ openerp.web_graph.PivotTable = openerp.web.Class.extend({ }, get_total: function (header) { - if (header) { - return this.get_values(header.id, this.get_other_root(header).headers[0].id); - } - return this.get_values(this.rows.headers[0].id, this.cols.headers[0].id); + return (header) ? this.get_values(header.id, this.get_other_root(header).headers[0].id) + : this.get_values(this.rows.headers[0].id, this.cols.headers[0].id); }, get_other_root: function (header) { @@ -190,7 +185,7 @@ openerp.web_graph.PivotTable = openerp.web.Class.extend({ fold_with_depth: function (root, depth) { var self = this; _.each(this._get_headers_with_depth(root.headers, depth), function (header) { - self.fold(header, true); + self.fold(header); }); }, @@ -338,25 +333,24 @@ openerp.web_graph.PivotTable = openerp.web.Class.extend({ }); groupbys.push([]); - var def_array = _.map(groupbys, function (groupby) { + var get_data_requests = _.map(groupbys, function (groupby) { return self.get_groups(groupby, visible_fields, self.domain); }); - return $.when.apply(null, def_array).then(function () { + return $.when.apply(null, get_data_requests).then(function () { var data = Array.prototype.slice.call(arguments), row_data = data[0], col_data = (cols.length !== 0) ? data[data.length - 2] : [], - total = data[data.length - 1][0]; + has_data = data[data.length - 1][0]; - return (total === undefined) ? undefined - : self.format_data(total, col_data, row_data, data); + return has_data && self.format_data(col_data, row_data, data); }); }, get_groups: function (groupbys, fields, domain, path) { - path = path || []; var self = this, groupby = (groupbys.length) ? groupbys[0] : []; + path = path || []; return this._query_db(groupby, fields, domain, path).then(function (groups) { if (groupbys.length > 1) { @@ -393,7 +387,7 @@ openerp.web_graph.PivotTable = openerp.web.Class.extend({ // if field is a fieldname, returns field, if field is field_id:interval, retuns field_id raw_field: function (field) { - return (_.contains(field, ':')) ? field.split(':')[0] : field; + return field.split(':')[0]; }, // add the path to the group and sanitize the value... @@ -418,7 +412,7 @@ openerp.web_graph.PivotTable = openerp.web.Class.extend({ return group; }, - format_data: function (total, col_data, row_data, cell_data) { + format_data: function (col_data, row_data, cell_data) { var self = this, dim_row = this.rows.groupby.length, dim_col = this.cols.groupby.length, @@ -450,12 +444,10 @@ openerp.web_graph.PivotTable = openerp.web.Class.extend({ _.each(data, function (group) { var attr = group.attributes, path = attr.grouped_on ? current_path.concat(attr.value) : current_path, - values = _.map(self.measures, function (measure) { - return (measure.field === '__count') ? attr.length : attr.aggregates[measure.field]; - }); + values = _.map(self.measures, function (measure) { return attr.aggregates[measure.field]; }), + row = _.find(rows, function (header) { return _.isEqual(header.path, path.slice(index)); }), + col = _.find(cols, function (header) { return _.isEqual(header.path, path.slice(0, index)); }); - var row = _.find(rows, function (header) { return _.isEqual(header.path, path.slice(index)); }); - var col = _.find(cols, function (header) { return _.isEqual(header.path, path.slice(0, index)); }); self.add_cell(row.id, col.id, values); if (group.children) { self.make_cells (group.children, index, path, rows, cols); -- cgit v1.2.3 From 31374c2eeffe824188b1a43768bc216a86d29b03 Mon Sep 17 00:00:00 2001 From: Gery Debongnie Date: Tue, 28 Jan 2014 12:10:22 +0100 Subject: [IMP] this commit translates the hardcoded strings that appears in graph view (addon web_graph) bzr revid: ged@openerp.com-20140128111022-ghoxwvlmywzr2yke --- addons/web_graph/static/src/js/pivot_table.js | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'addons/web_graph/static/src/js/pivot_table.js') diff --git a/addons/web_graph/static/src/js/pivot_table.js b/addons/web_graph/static/src/js/pivot_table.js index a5bfba3c09a..89ca36f3b61 100644 --- a/addons/web_graph/static/src/js/pivot_table.js +++ b/addons/web_graph/static/src/js/pivot_table.js @@ -4,6 +4,9 @@ (function () { 'use strict'; +var _lt = openerp.web._lt; +var _t = openerp.web._t; + // PivotTable requires a call to update_data after initialization openerp.web_graph.PivotTable = openerp.web.Class.extend({ @@ -13,7 +16,7 @@ openerp.web_graph.PivotTable = openerp.web.Class.extend({ this.no_data = true; this.model = model; this.fields = fields; - this.fields.__count = {type: 'integer', string:'Quantity'}; + this.fields.__count = {type: 'integer', string:_t('Quantity')}; this.measures = options.measures || []; this.rows = { groupby: options.row_groupby, headers: null }; this.cols = { groupby: options.col_groupby, headers: null }; @@ -397,11 +400,11 @@ openerp.web_graph.PivotTable = openerp.web.Class.extend({ grouped_on = attrs.grouped_on ? this.raw_field(attrs.grouped_on) : false; if (value === false) { - group.attributes.value = 'undefined'; + group.attributes.value = _t('undefined'); } else if (grouped_on && this.fields[grouped_on].type === 'selection') { var selection = this.fields[grouped_on].selection, value_lookup = _.where(selection, {0:value}); - group.attributes.value = value_lookup ? value_lookup[0][1] : 'undefined'; + group.attributes.value = value_lookup ? value_lookup[0][1] : _t('undefined'); } else if (value instanceof Array) { group.attributes.value = value[1]; } -- cgit v1.2.3 From ad76309fbe29f6d4d2d26393bc8d2b1c595a124f Mon Sep 17 00:00:00 2001 From: Gery Debongnie Date: Tue, 28 Jan 2014 14:26:25 +0100 Subject: [IMP] makes the graph view in pivot table mode always display 'Total' instead of the current measure/title (addon web_graph) bzr revid: ged@openerp.com-20140128132625-pk21iuhuffvx6814 --- addons/web_graph/static/src/js/pivot_table.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'addons/web_graph/static/src/js/pivot_table.js') diff --git a/addons/web_graph/static/src/js/pivot_table.js b/addons/web_graph/static/src/js/pivot_table.js index 89ca36f3b61..fccb1e4bffa 100644 --- a/addons/web_graph/static/src/js/pivot_table.js +++ b/addons/web_graph/static/src/js/pivot_table.js @@ -238,7 +238,7 @@ openerp.web_graph.PivotTable = openerp.web.Class.extend({ }, make_header: function (group, parent) { - var title = parent ? group.attributes.value : ''; + var title = parent ? group.attributes.value : _t('Total'); return { id: _.uniqueId(), path: parent ? parent.path.concat(title) : [], -- cgit v1.2.3 From 9344f2f851823624793359c366fb6beeb1ab0242 Mon Sep 17 00:00:00 2001 From: Gery Debongnie Date: Tue, 28 Jan 2014 16:11:57 +0100 Subject: [FIX] changes the hardcoded string 'undefined' into 'Undefined' in pivot table (addon web_graph) bzr revid: ged@openerp.com-20140128151157-3opcfcockwrgr3kx --- addons/web_graph/static/src/js/pivot_table.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'addons/web_graph/static/src/js/pivot_table.js') diff --git a/addons/web_graph/static/src/js/pivot_table.js b/addons/web_graph/static/src/js/pivot_table.js index fccb1e4bffa..770519e52c2 100644 --- a/addons/web_graph/static/src/js/pivot_table.js +++ b/addons/web_graph/static/src/js/pivot_table.js @@ -400,11 +400,11 @@ openerp.web_graph.PivotTable = openerp.web.Class.extend({ grouped_on = attrs.grouped_on ? this.raw_field(attrs.grouped_on) : false; if (value === false) { - group.attributes.value = _t('undefined'); + group.attributes.value = _t('Undefined'); } else if (grouped_on && this.fields[grouped_on].type === 'selection') { var selection = this.fields[grouped_on].selection, value_lookup = _.where(selection, {0:value}); - group.attributes.value = value_lookup ? value_lookup[0][1] : _t('undefined'); + group.attributes.value = value_lookup ? value_lookup[0][1] : _t('Undefined'); } else if (value instanceof Array) { group.attributes.value = value[1]; } -- cgit v1.2.3 From 882fde48f087121b0a58888c0c0ae9734fe8b419 Mon Sep 17 00:00:00 2001 From: Gery Debongnie Date: Mon, 3 Feb 2014 12:33:32 +0100 Subject: [IMP] work in progress: adds the export functionality in graph view (addon web_graph) bzr revid: ged@openerp.com-20140203113332-fvr9cra2dhj4h0ju --- addons/web_graph/static/src/js/pivot_table.js | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'addons/web_graph/static/src/js/pivot_table.js') diff --git a/addons/web_graph/static/src/js/pivot_table.js b/addons/web_graph/static/src/js/pivot_table.js index 770519e52c2..f77d49f9a1a 100644 --- a/addons/web_graph/static/src/js/pivot_table.js +++ b/addons/web_graph/static/src/js/pivot_table.js @@ -127,6 +127,10 @@ openerp.web_graph.PivotTable = openerp.web.Class.extend({ return this._get_headers_with_depth(this.rows.headers, depth); }, + get_ancestor_leaves: function (header) { + return _.where(this.get_ancestors_and_self(header), {expanded:false}); + }, + // return all non expanded rows get_rows_leaves: function () { return _.where(this.rows.headers, {expanded:false}); -- cgit v1.2.3