[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
This commit is contained in:
parent
f404bf8b40
commit
2cafcfbde7
|
@ -1,10 +1,11 @@
|
|||
.graph_main_content td {
|
||||
font-size: 12px;
|
||||
/*background: #fff;*/
|
||||
margin: 45px;
|
||||
border-collapse: collapse;
|
||||
text-align: left;
|
||||
vertical-align: middle;
|
||||
border-bottom: 1px solid #ccc;
|
||||
padding: 6px 8px;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.graph_measure_selection .oe_selected {
|
||||
|
@ -12,12 +13,10 @@
|
|||
}
|
||||
|
||||
.graph_measure_selection .oe_selected:before {
|
||||
/*content: "W";*/
|
||||
content: "\f00c";
|
||||
width: 20px;
|
||||
display: inline-block;
|
||||
font-family: FontAwesome;
|
||||
|
||||
}
|
||||
|
||||
.graph_measure_selection li {
|
||||
|
@ -35,19 +34,12 @@
|
|||
.graph_main_content thead {
|
||||
border: 1px solid #6678b1;
|
||||
border-bottom: 2px solid #6678b1;
|
||||
/*color: #039;*/
|
||||
}
|
||||
|
||||
.graph_main_content tbody td{
|
||||
border: 1px solid #ccc;
|
||||
}
|
||||
|
||||
.graph_main_content td {
|
||||
border-bottom: 1px solid #ccc;
|
||||
padding: 6px 8px;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
td.graph_border {
|
||||
color: #039;
|
||||
text-align: left;
|
||||
|
@ -77,19 +69,15 @@ span.web_graph_indent {
|
|||
font-size: 13px;
|
||||
padding: 4px 0;
|
||||
background: #e8e8e8 !important;
|
||||
background: #e8e8e8 !important;
|
||||
border: 1px solid #cccccc;
|
||||
border: 1px solid rgba(0, 0, 0, 0.15);
|
||||
|
||||
font-color: !important black;
|
||||
background-color: #e8e8e8;
|
||||
font-color: !important black;
|
||||
text-shadow: none;
|
||||
background-color: #e8e8e8;
|
||||
|
||||
-moz-border-radius: 3px;
|
||||
-webkit-border-radius: 3px;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.graph_widget .dropdown-menu li a, .graph_widget .dropdown-menu li a:hover, .graph_widget .dropdown-menu li a:focus {
|
||||
color: black;
|
||||
text-decoration: none;
|
||||
|
@ -98,7 +86,6 @@ span.web_graph_indent {
|
|||
th.measure_row {
|
||||
color: black;
|
||||
font-size: 12px;
|
||||
/*border: 0 !important;*/
|
||||
padding:0px 5px 0px 5px ;
|
||||
margin:0;
|
||||
}
|
||||
|
|
|
@ -30,13 +30,14 @@ instance.web_graph.GraphView = instance.web.View.extend({
|
|||
var self = this,
|
||||
arch = fields_view_get.arch;
|
||||
|
||||
this.widget_config = {
|
||||
this.widget_config = {
|
||||
title: arch.attrs.string,
|
||||
stacked : (arch.attrs.stacked === 'True'),
|
||||
mode: (arch.attrs.type) ? arch.attrs.type : 'bar',
|
||||
measures: [],
|
||||
row_groupby: [],
|
||||
col_groupby: [],
|
||||
graph_view: this,
|
||||
};
|
||||
|
||||
_.each(arch.children, function (field) {
|
||||
|
@ -67,7 +68,7 @@ instance.web_graph.GraphView = instance.web.View.extend({
|
|||
|
||||
do_search: function (domain, context, group_by) {
|
||||
var self = this,
|
||||
col_group_by = this.get_col_groupbys_from_searchview();
|
||||
col_group_by = this.get_groupbys_from_searchview('ColGroupBy', 'col_group_by');
|
||||
|
||||
if (!this.graph_widget) {
|
||||
if (group_by.length) {
|
||||
|
@ -78,36 +79,23 @@ instance.web_graph.GraphView = instance.web.View.extend({
|
|||
}
|
||||
this.graph_widget = new openerp.web_graph.Graph(this, this.model, domain, this.widget_config);
|
||||
this.graph_widget.appendTo(this.$el);
|
||||
this.graph_widget.on('groupby_changed', this, this.proxy('register_groupby'));
|
||||
this.graph_widget.on('groupby_swapped', this, this.proxy('swap_groupby'));
|
||||
this.ViewManager.on('switch_mode', this, function (e) {
|
||||
this.ViewManager.on('switch_mode', this, function (e) {
|
||||
var domain = self.graph_widget.get_domain(),
|
||||
col_gb = self.get_col_groupbys_from_searchview(),
|
||||
row_gb = self.get_row_groupbys_from_searchview();
|
||||
col_gb = self.get_groupbys_from_searchview('ColGroupBy', 'col_group_by'),
|
||||
row_gb = self.get_groupbys_from_searchview('GroupBy', 'group_by');
|
||||
|
||||
if (e === 'graph') this.graph_widget.set(domain, row_gb, col_gb);
|
||||
if (e === 'graph') this.graph_widget.set(domain, row_gb, col_gb);
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.swapped) {
|
||||
this.swapped = false;
|
||||
return;
|
||||
}
|
||||
|
||||
this.graph_widget.set(domain, group_by, col_group_by);
|
||||
},
|
||||
|
||||
get_col_groupbys_from_searchview: function () {
|
||||
var facet = this.search_view.query.findWhere({category:'ColGroupBy'}),
|
||||
get_groupbys_from_searchview: function (cat_name, cat_field) {
|
||||
var facet = this.search_view.query.findWhere({category:cat_name}),
|
||||
groupby_list = facet ? facet.values.models : [];
|
||||
return _.map(groupby_list, function (g) { return g.attributes.value.attrs.context.col_group_by; });
|
||||
},
|
||||
|
||||
get_row_groupbys_from_searchview: function () {
|
||||
var facet = this.search_view.query.findWhere({category:'GroupBy'}),
|
||||
groupby_list = facet ? facet.values.models : [];
|
||||
return _.map(groupby_list, function (g) { return g.attributes.value.attrs.context.group_by; });
|
||||
return _.map(groupby_list, function (g) { return g.attributes.value.attrs.context[cat_field]; });
|
||||
},
|
||||
|
||||
do_show: function () {
|
||||
|
@ -120,14 +108,13 @@ instance.web_graph.GraphView = instance.web.View.extend({
|
|||
// ----------------------------------------------------------------------
|
||||
|
||||
// add groupby to the search view
|
||||
register_groupby: function() {
|
||||
register_groupby: function(row_groupby, col_groupby) {
|
||||
var query = this.search_view.query;
|
||||
|
||||
if (!_.has(this.search_view, '_s_groupby')) { return; }
|
||||
|
||||
// add row groupbys
|
||||
var row_groupby = this.graph_widget.get_row_groupby(),
|
||||
row_facet = this.make_row_groupby_facets(row_groupby),
|
||||
var row_facet = this.make_row_groupby_facets(row_groupby),
|
||||
row_search_facet = query.findWhere({category:'GroupBy'});
|
||||
|
||||
if (row_search_facet) {
|
||||
|
@ -138,8 +125,7 @@ instance.web_graph.GraphView = instance.web.View.extend({
|
|||
}
|
||||
}
|
||||
// add col groupbys
|
||||
var col_groupby = this.graph_widget.get_col_groupby(),
|
||||
col_facet = this.make_col_groupby_facets(col_groupby),
|
||||
var col_facet = this.make_col_groupby_facets(col_groupby),
|
||||
col_search_facet = query.findWhere({category:'ColGroupBy'});
|
||||
|
||||
if (col_search_facet) {
|
||||
|
@ -151,11 +137,6 @@ instance.web_graph.GraphView = instance.web.View.extend({
|
|||
}
|
||||
},
|
||||
|
||||
swap_groupby: function () {
|
||||
this.swap = true;
|
||||
this.register_groupby();
|
||||
},
|
||||
|
||||
make_row_groupby_facets: function(groupbys) {
|
||||
return {
|
||||
category:'GroupBy',
|
||||
|
@ -178,9 +159,10 @@ instance.web_graph.GraphView = instance.web.View.extend({
|
|||
return _.map(groupbys, function (groupby) {
|
||||
var context = {};
|
||||
context[category] = groupby.field;
|
||||
var value = (category === 'group_by') ? groupby.filter : {attrs:{domain: [], context: context}};
|
||||
return {
|
||||
label: groupby.string,
|
||||
value: {attrs:{domain: [], context: context}}
|
||||
label: groupby.string,
|
||||
value: value
|
||||
};
|
||||
});
|
||||
},
|
||||
|
@ -192,7 +174,6 @@ instance.web_graph.GraphView = instance.web.View.extend({
|
|||
},
|
||||
|
||||
});
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
var QWeb = openerp.web.qweb;
|
||||
nv.dev = false; // sets nvd3 library in production mode
|
||||
|
||||
openerp.web_graph.Graph = openerp.web.Widget.extend(openerp.EventDispatcherMixin, {
|
||||
openerp.web_graph.Graph = openerp.web.Widget.extend({
|
||||
template: 'GraphWidget',
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
@ -21,7 +21,9 @@ openerp.web_graph.Graph = openerp.web.Widget.extend(openerp.EventDispatcherMixin
|
|||
this.title = options.title || 'Graph';
|
||||
this.visible_ui = options.visible_ui || true;
|
||||
this.bar_ui = options.bar_ui || 'group';
|
||||
this.graph_view = options.graph_view || null;
|
||||
this.pivot_options = options;
|
||||
this.important_fields = this.get_search_fields();
|
||||
},
|
||||
|
||||
start: function() {
|
||||
|
@ -39,58 +41,48 @@ openerp.web_graph.Graph = openerp.web.Widget.extend(openerp.EventDispatcherMixin
|
|||
this.$('.graph_heatmap label').addClass('disabled');
|
||||
}
|
||||
|
||||
var def1 = this.get_search_fields().then(function (f) {
|
||||
self.important_fields = f;
|
||||
});
|
||||
|
||||
var def2 = this.model.call('fields_get', []).then(function (f) {
|
||||
return this.model.call('fields_get', []).then(function (f) {
|
||||
self.fields = f;
|
||||
self.fields.__count = {string: 'Quantity', type: 'integer'};
|
||||
self.measure_list = self.get_measures();
|
||||
self.add_measures_to_options();
|
||||
});
|
||||
|
||||
return $.when(def1, def2).then(function () {
|
||||
self.pivot_options.row_groupby = self.create_field_values(self.pivot_options.row_groupby || []);
|
||||
self.pivot_options.col_groupby = self.create_field_values(self.pivot_options.col_groupby || []);
|
||||
self.pivot_options.measures = self.create_field_values(self.pivot_options.measures || [{field:'__count', type: 'integer', string:'Quantity'}]);
|
||||
self.pivot = new openerp.web_graph.PivotTable(self.model, self.domain, self.fields, self.pivot_options);
|
||||
self.pivot.on('redraw_required', self, self.proxy('display_data'));
|
||||
self.pivot.on('groupby_changed', self, function () { self.trigger('groupby_changed'); });
|
||||
self.pivot.on('groupby_swapped', self, function () { self.trigger('groupby_swapped'); });
|
||||
self.pivot.update_data().then(function () {
|
||||
self.display_data();
|
||||
if (self.graph_view) {
|
||||
self.graph_view.register_groupby(self.pivot.rows.groupby, self.pivot.cols.groupby);
|
||||
}
|
||||
});
|
||||
openerp.web.bus.on('click', self, function () {
|
||||
if (self.dropdown) {
|
||||
self.dropdown.remove();
|
||||
self.dropdown = null;
|
||||
}
|
||||
});
|
||||
self.pivot.activate();
|
||||
self.put_measure_checkmarks();
|
||||
self.trigger('groupby_changed');
|
||||
});
|
||||
},
|
||||
|
||||
// this method gets the fields that appear in the search view, under the
|
||||
// 'Groupby' heading
|
||||
get_search_fields: function () {
|
||||
var options = {model:this.model, view_type: 'search'},
|
||||
result = [];
|
||||
var search_view = openerp.client.action_manager.inner_widget.searchview;
|
||||
|
||||
return openerp.web.fields_view_get(options).then(function (search_view) {
|
||||
var groups = _.select(search_view.arch.children, function (c) {
|
||||
return (c.tag === 'group') && (c.attrs.string != 'Display');
|
||||
});
|
||||
_.each(groups, function(g) {
|
||||
_.each(g.children, function (g) {
|
||||
if (g.attrs.context) {
|
||||
var field_id = py.eval(g.attrs.context).group_by;
|
||||
if (field_id) {
|
||||
if (field_id instanceof Array) {
|
||||
result.concat(field_id);
|
||||
} else {
|
||||
result.push(field_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
return result;
|
||||
var groupbygroups = _(search_view.inputs).select(function (g) {
|
||||
return g instanceof openerp.web.search.GroupbyGroup;
|
||||
});
|
||||
|
||||
var filters = [].concat.apply([], _.pluck(groupbygroups, 'filters'));
|
||||
|
||||
return _.map(filters, function (filter) {
|
||||
return {
|
||||
field: py.eval(filter.attrs.context).group_by,
|
||||
string: filter.attrs.string,
|
||||
filter: filter
|
||||
};
|
||||
});
|
||||
},
|
||||
|
||||
|
@ -119,12 +111,33 @@ openerp.web_graph.Graph = openerp.web.Widget.extend(openerp.EventDispatcherMixin
|
|||
// Configuration methods
|
||||
// ----------------------------------------------------------------------
|
||||
set: function (domain, row_groupby, col_groupby) {
|
||||
if (this.pivot) {
|
||||
this.pivot.set(domain, row_groupby, col_groupby);
|
||||
} else {
|
||||
if (!this.pivot) {
|
||||
this.pivot_options.domain = domain;
|
||||
this.pivot_options.row_groupby = row_groupby;
|
||||
this.pivot_options.col_groupby = col_groupby;
|
||||
return;
|
||||
}
|
||||
var row_gbs = this.create_field_values(row_groupby),
|
||||
col_gbs = this.create_field_values(col_groupby),
|
||||
dom_changed = !_.isEqual(this.pivot.domain, domain),
|
||||
row_gb_changed = !this.equal_groupby(row_gbs, this.pivot.rows.groupby),
|
||||
col_gb_changed = !this.equal_groupby(col_gbs, this.pivot.cols.groupby),
|
||||
row_reduced = is_strict_beginning_of(row_gbs, this.pivot.rows.groupby),
|
||||
col_reduced = is_strict_beginning_of(col_gbs, this.pivot.cols.groupby);
|
||||
|
||||
if (!dom_changed && row_reduced && !col_gb_changed) {
|
||||
this.pivot.fold_with_depth(this.pivot.rows, row_gbs.length);
|
||||
this.display_data();
|
||||
return;
|
||||
}
|
||||
if (!dom_changed && col_reduced && !row_gb_changed) {
|
||||
this.pivot.fold_with_depth(this.pivot.cols, col_gbs.length);
|
||||
this.display_data();
|
||||
return;
|
||||
}
|
||||
|
||||
if (dom_changed || row_gb_changed || col_gb_changed) {
|
||||
this.pivot.set(domain, row_gbs, col_gbs).then(this.proxy('display_data'));
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -148,20 +161,39 @@ openerp.web_graph.Graph = openerp.web.Widget.extend(openerp.EventDispatcherMixin
|
|||
this.display_data();
|
||||
},
|
||||
|
||||
// returns the row groupbys as a list of fields (not the representation used
|
||||
// internally by pivot table)
|
||||
get_row_groupby: function () {
|
||||
return (this.pivot) ? this.pivot.rows.groupby : this.pivot_options.row_groupby;
|
||||
// compare groupby, ignoring the 'interval' attribute of dates...
|
||||
// this is necessary to avoid problems with the groupby received by the
|
||||
// context which does 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;
|
||||
},
|
||||
|
||||
get_col_groupby: function () {
|
||||
return (this.pivot) ? this.pivot.cols.groupby : this.pivot_options.col_groupby;
|
||||
equal_value: function (val1, val2) {
|
||||
return ((val1.field === val2.field) && (val1.string === val2.string) && (val1.type === val2.type));
|
||||
},
|
||||
|
||||
get_domain: function () {
|
||||
return (this.pivot) ? this.pivot.domain : this.pivot_options.domain;
|
||||
create_field_value: function (f) {
|
||||
var important_field = _.findWhere(this.important_fields, {field:f}),
|
||||
string = important_field ? important_field.string : this.fields[f].string,
|
||||
result = {field: f, string: string, type: this.fields[f].type };
|
||||
|
||||
if (important_field) {
|
||||
result.filter = important_field.filter;
|
||||
}
|
||||
return result;
|
||||
},
|
||||
|
||||
create_field_values: function (field_ids) {
|
||||
var self = this;
|
||||
return _.map(field_ids, function (f) { return self.create_field_value(f); });
|
||||
},
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// UI code
|
||||
// ----------------------------------------------------------------------
|
||||
|
@ -183,8 +215,14 @@ openerp.web_graph.Graph = openerp.web.Widget.extend(openerp.EventDispatcherMixin
|
|||
measure_selection: function (event) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
var measure = event.target.attributes['data-choice'].nodeValue;
|
||||
this.pivot.toggle_measure(measure);
|
||||
var measure_field = event.target.attributes['data-choice'].nodeValue;
|
||||
var measure = {
|
||||
field: measure_field,
|
||||
type: this.fields[measure_field].type,
|
||||
string: this.fields[measure_field].string
|
||||
};
|
||||
|
||||
this.pivot.toggle_measure(measure).then(this.proxy('display_data'));
|
||||
this.put_measure_checkmarks();
|
||||
},
|
||||
|
||||
|
@ -216,16 +254,13 @@ openerp.web_graph.Graph = openerp.web.Widget.extend(openerp.EventDispatcherMixin
|
|||
}
|
||||
break;
|
||||
case 'swap_axis':
|
||||
this.pivot.swap_axis();
|
||||
this.swap_axis();
|
||||
break;
|
||||
case 'expand_all':
|
||||
this.pivot.expand_all();
|
||||
this.pivot.expand_all().then(this.proxy('display_data'));
|
||||
break;
|
||||
case 'update_values':
|
||||
this.pivot.update_data();
|
||||
break;
|
||||
case 'export_data':
|
||||
// Export code... To do...
|
||||
this.pivot.update_data().then(this.proxy('display_data'));
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
@ -249,16 +284,16 @@ openerp.web_graph.Graph = openerp.web.Widget.extend(openerp.EventDispatcherMixin
|
|||
self = this;
|
||||
|
||||
if (header.expanded) {
|
||||
this.pivot.fold(header);
|
||||
this.fold(header);
|
||||
} else {
|
||||
if (header.path.length < header.root.groupby.length) {
|
||||
this.pivot.expand(id);
|
||||
this.expand(id);
|
||||
} else {
|
||||
if (!this.important_fields.length) {
|
||||
return;
|
||||
}
|
||||
var fields = _.map(this.important_fields, function (field) {
|
||||
return {id: field, value: self.fields[field].string, type:self.fields[field].type};
|
||||
return {id: field.field, value: field.string, type:self.fields[field.field].type};
|
||||
});
|
||||
this.dropdown = $(QWeb.render('field_selection', {fields:fields, header_id:id}));
|
||||
$(event.target).after(this.dropdown);
|
||||
|
@ -277,12 +312,46 @@ openerp.web_graph.Graph = openerp.web.Widget.extend(openerp.EventDispatcherMixin
|
|||
event.preventDefault();
|
||||
if (this.fields[field_id].type === 'date' || this.fields[field_id].type === 'datetime') {
|
||||
interval = event.target.attributes['data-interval'].nodeValue;
|
||||
this.pivot.expand(id, {field: field_id, interval: interval});
|
||||
this.expand(id, {field: field_id, interval: interval});
|
||||
} else {
|
||||
this.pivot.expand(id, field_id);
|
||||
this.expand(id, field_id);
|
||||
}
|
||||
},
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// Pivot Table integration
|
||||
// ----------------------------------------------------------------------
|
||||
expand: function (header_id, field_id) {
|
||||
var self = this,
|
||||
header = this.pivot.get_header(header_id),
|
||||
update_groupby = !!field_id,
|
||||
groupby = (update_groupby) ? this.create_field_value(field_id)
|
||||
: header.root.groupby[header.path.length];
|
||||
|
||||
this.pivot.expand(header_id, groupby).then(function () {
|
||||
if (update_groupby && self.graph_view) {
|
||||
self.graph_view.register_groupby(self.pivot.rows.groupby, self.pivot.cols.groupby);
|
||||
}
|
||||
self.display_data();
|
||||
});
|
||||
|
||||
},
|
||||
|
||||
fold: function (header) {
|
||||
var update_groupby = this.pivot.fold(header);
|
||||
|
||||
this.display_data();
|
||||
if (update_groupby && this.graph_view) {
|
||||
this.graph_view.register_groupby(this.pivot.rows.groupby, this.pivot.cols.groupby);
|
||||
}
|
||||
},
|
||||
|
||||
swap_axis: function () {
|
||||
this.pivot.swap_axis();
|
||||
this.display_data();
|
||||
this.graph_view.register_groupby(this.pivot.rows.groupby, this.pivot.cols.groupby);
|
||||
},
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// Main display method
|
||||
// ----------------------------------------------------------------------
|
||||
|
@ -290,6 +359,8 @@ openerp.web_graph.Graph = openerp.web.Widget.extend(openerp.EventDispatcherMixin
|
|||
this.$('.graph_main_content svg').remove();
|
||||
this.$('.graph_main_content div').remove();
|
||||
this.table.empty();
|
||||
this.width = this.$el.width();
|
||||
this.height = Math.min(Math.max(document.documentElement.clientHeight - 116 - 60, 250), Math.round(0.8*this.$el.width()));
|
||||
|
||||
if (this.visible_ui) {
|
||||
this.$('.graph_header').css('display', 'block');
|
||||
|
@ -304,8 +375,6 @@ openerp.web_graph.Graph = openerp.web.Widget.extend(openerp.EventDispatcherMixin
|
|||
} else {
|
||||
this.$('.graph_main_content').append($('<div><svg></svg></div>'));
|
||||
this.svg = this.$('.graph_main_content svg')[0];
|
||||
this.width = this.$el.width();
|
||||
this.height = Math.min(Math.max(document.documentElement.clientHeight - 116 - 60, 250), Math.round(0.8*this.$el.width()));
|
||||
this[this.mode]();
|
||||
}
|
||||
}
|
||||
|
@ -642,4 +711,16 @@ openerp.web_graph.Graph = openerp.web.Widget.extend(openerp.EventDispatcherMixin
|
|||
},
|
||||
|
||||
});
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
})();
|
||||
|
|
|
@ -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(); }
|
||||
}
|
||||
this.measures = measures;
|
||||
return 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});
|
||||
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);
|
||||
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;
|
||||
|
||||
if (dom_changed) {
|
||||
this.domain = domain;
|
||||
}
|
||||
if (row_gb_changed) { this.rows.headers = null; }
|
||||
if (col_gb_changed) { this.cols.headers = null; }
|
||||
|
||||
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();
|
||||
}
|
||||
return 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));
|
||||
},
|
||||
|
||||
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
|
||||
// ----------------------------------------------------------------------
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
})();
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue