2011-04-15 06:42:41 +00:00
|
|
|
/*---------------------------------------------------------
|
2011-09-05 12:28:15 +00:00
|
|
|
* OpenERP web_graph
|
2011-04-15 06:42:41 +00:00
|
|
|
*---------------------------------------------------------*/
|
2013-11-08 15:41:14 +00:00
|
|
|
|
2013-11-12 08:38:27 +00:00
|
|
|
/* jshint undef: false */
|
|
|
|
|
2011-04-15 06:42:41 +00:00
|
|
|
|
2012-04-17 12:48:30 +00:00
|
|
|
openerp.web_graph = function (instance) {
|
2013-11-13 10:50:59 +00:00
|
|
|
'use strict';
|
2011-06-17 13:25:50 +00:00
|
|
|
|
2012-06-07 14:17:12 +00:00
|
|
|
var _lt = instance.web._lt;
|
2013-01-25 07:02:40 +00:00
|
|
|
var _t = instance.web._t;
|
2013-11-12 13:53:44 +00:00
|
|
|
var QWeb = instance.web.qweb;
|
2012-05-07 08:19:08 +00:00
|
|
|
|
2012-04-17 12:48:30 +00:00
|
|
|
instance.web.views.add('graph', 'instance.web_graph.GraphView');
|
2013-11-08 13:08:06 +00:00
|
|
|
|
2013-11-08 15:20:48 +00:00
|
|
|
/**
|
2013-11-18 09:07:15 +00:00
|
|
|
* GraphView view. It mostly contains a widget (PivotTable), some data, and
|
|
|
|
* calls to charts function.
|
2013-11-08 15:20:48 +00:00
|
|
|
*/
|
2012-04-17 12:48:30 +00:00
|
|
|
instance.web_graph.GraphView = instance.web.View.extend({
|
2013-11-08 13:08:06 +00:00
|
|
|
template: 'GraphView',
|
2011-12-16 13:00:00 +00:00
|
|
|
display_name: _lt('Graph'),
|
2013-11-08 13:08:06 +00:00
|
|
|
view_type: 'graph',
|
2013-11-15 16:32:09 +00:00
|
|
|
mode: 'pivot', // pivot, bar_chart, line_chart or pie_chart
|
2013-11-18 12:53:20 +00:00
|
|
|
pivot_table: null,
|
2013-11-12 11:31:34 +00:00
|
|
|
|
2013-11-08 13:08:06 +00:00
|
|
|
events: {
|
|
|
|
'click .graph_mode_selection li' : function (event) {
|
|
|
|
event.preventDefault();
|
2013-11-15 16:32:09 +00:00
|
|
|
this.mode = event.target.attributes['data-mode'].nodeValue;
|
2013-11-12 16:10:34 +00:00
|
|
|
this.display_data();
|
2013-11-08 13:08:06 +00:00
|
|
|
},
|
|
|
|
},
|
2011-04-15 06:42:41 +00:00
|
|
|
|
2013-11-08 13:08:06 +00:00
|
|
|
view_loading: function (fields_view_get) {
|
2013-11-08 15:20:48 +00:00
|
|
|
var self = this;
|
2013-11-13 10:50:59 +00:00
|
|
|
var model = new instance.web.Model(fields_view_get.model, {group_by_no_leaf: true});
|
2013-11-18 12:53:20 +00:00
|
|
|
var domain = [];
|
|
|
|
var col_groupby = [];
|
|
|
|
var row_groupby = [];
|
|
|
|
var measure = null;
|
|
|
|
var fields;
|
|
|
|
var important_fields = [];
|
2013-11-08 15:20:48 +00:00
|
|
|
|
|
|
|
// get the default groupbys and measure defined in the field view
|
|
|
|
_.each(fields_view_get.arch.children, function (field) {
|
|
|
|
if ('name' in field.attrs) {
|
|
|
|
if ('operator' in field.attrs) {
|
2013-11-18 12:53:20 +00:00
|
|
|
measure = field.attrs.name;
|
2013-11-08 15:20:48 +00:00
|
|
|
} else {
|
2013-11-18 12:53:20 +00:00
|
|
|
row_groupby.push(field.attrs.name);
|
2013-11-08 15:20:48 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2013-11-13 15:47:31 +00:00
|
|
|
// get the most important fields (of the model) by looking at the
|
|
|
|
// groupby filters defined in the search view
|
|
|
|
var load_view = instance.web.fields_view_get({
|
|
|
|
model: model,
|
|
|
|
view_type: 'search',
|
2013-11-12 08:38:27 +00:00
|
|
|
});
|
2013-11-08 15:20:48 +00:00
|
|
|
|
2013-11-13 15:47:31 +00:00
|
|
|
var important_fields_def = $.when(load_view).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;
|
2013-11-18 12:53:20 +00:00
|
|
|
important_fields.push(field_id);
|
2013-11-13 15:47:31 +00:00
|
|
|
}
|
|
|
|
});
|
|
|
|
});
|
2013-11-14 10:34:46 +00:00
|
|
|
});
|
2013-11-13 15:47:31 +00:00
|
|
|
|
|
|
|
// get the fields descriptions from the model
|
|
|
|
var field_descr_def = model.call('fields_get', [])
|
2013-11-18 12:53:20 +00:00
|
|
|
.then(function (fs) { fields = fs; });
|
2013-11-13 15:47:31 +00:00
|
|
|
|
|
|
|
return $.when(important_fields_def, field_descr_def)
|
|
|
|
.then(function () {
|
2013-11-15 16:32:09 +00:00
|
|
|
self.data = {
|
|
|
|
model: model,
|
2013-11-18 12:53:20 +00:00
|
|
|
domain: domain,
|
|
|
|
fields: fields,
|
|
|
|
important_fields: important_fields,
|
|
|
|
measure: measure,
|
|
|
|
measure_label: fields[measure].string,
|
2013-11-15 16:32:09 +00:00
|
|
|
col_groupby: [],
|
2013-11-18 12:53:20 +00:00
|
|
|
row_groupby: row_groupby,
|
2013-11-15 16:32:09 +00:00
|
|
|
groups: [],
|
|
|
|
total: null,
|
|
|
|
};
|
2013-11-13 15:47:31 +00:00
|
|
|
});
|
2013-11-12 16:10:34 +00:00
|
|
|
},
|
|
|
|
|
2013-11-13 09:18:07 +00:00
|
|
|
display_data : function () {
|
2013-11-15 16:32:09 +00:00
|
|
|
var content = this.$el.filter('.graph_main_content');
|
|
|
|
content.find('svg').remove();
|
|
|
|
var self = this;
|
2013-11-13 09:18:07 +00:00
|
|
|
if (this.mode === 'pivot') {
|
|
|
|
this.pivot_table.show();
|
|
|
|
} else {
|
|
|
|
this.pivot_table.hide();
|
2013-11-15 16:32:09 +00:00
|
|
|
content.append('<svg></svg>');
|
|
|
|
var view_fields = this.data.row_groupby.concat(this.data.measure, this.data.col_groupby);
|
|
|
|
query_groups(this.data.model, view_fields, this.data.domain, this.data.row_groupby).then(function (groups) {
|
|
|
|
Charts[self.mode](groups, self.data.measure, self.data.measure_label);
|
|
|
|
});
|
|
|
|
|
2013-11-13 09:18:07 +00:00
|
|
|
}
|
|
|
|
},
|
|
|
|
|
2013-11-08 15:20:48 +00:00
|
|
|
do_search: function (domain, context, group_by) {
|
2013-11-15 16:32:09 +00:00
|
|
|
this.data.domain = new instance.web.CompoundDomain(domain);
|
2013-11-18 12:53:20 +00:00
|
|
|
|
|
|
|
if (this.pivot_table) {
|
2013-11-18 13:07:56 +00:00
|
|
|
this.pivot_table.draw(true);
|
2013-11-18 12:53:20 +00:00
|
|
|
} else {
|
|
|
|
this.pivot_table = new PivotTable(this.data);
|
|
|
|
this.pivot_table.appendTo('.graph_main_content');
|
|
|
|
}
|
2013-11-13 10:50:59 +00:00
|
|
|
this.display_data();
|
2011-05-06 12:41:08 +00:00
|
|
|
},
|
2012-05-07 09:40:59 +00:00
|
|
|
|
2013-11-08 11:32:10 +00:00
|
|
|
do_show: function () {
|
2012-01-03 16:06:50 +00:00
|
|
|
this.do_push_state({});
|
|
|
|
return this._super();
|
2012-05-07 08:19:08 +00:00
|
|
|
},
|
2013-11-08 15:20:48 +00:00
|
|
|
|
2013-11-08 13:08:06 +00:00
|
|
|
});
|
|
|
|
|
2013-11-15 15:16:59 +00:00
|
|
|
|
2013-11-08 15:20:48 +00:00
|
|
|
/**
|
2013-11-15 16:32:09 +00:00
|
|
|
* PivotTable widget. It displays the data in tabular data and allows the
|
|
|
|
* user to drill down and up in the table
|
2013-11-08 15:20:48 +00:00
|
|
|
*/
|
2013-11-15 16:32:09 +00:00
|
|
|
var PivotTable = instance.web.Widget.extend({
|
|
|
|
template: 'pivot_table',
|
2013-11-18 12:53:20 +00:00
|
|
|
data: null,
|
|
|
|
headers: [],
|
2013-11-15 16:32:09 +00:00
|
|
|
rows: [],
|
|
|
|
cols: [],
|
2013-11-18 15:26:20 +00:00
|
|
|
id_seed : 0,
|
2013-11-13 09:26:46 +00:00
|
|
|
|
2013-11-13 15:47:31 +00:00
|
|
|
events: {
|
2013-11-15 12:13:15 +00:00
|
|
|
'click .web_graph_click' : function (event) {
|
2013-11-13 15:47:31 +00:00
|
|
|
event.preventDefault();
|
2013-11-14 10:34:46 +00:00
|
|
|
|
2013-11-18 15:26:20 +00:00
|
|
|
if (event.target.attributes['data-row-id'] !== undefined) {
|
|
|
|
this.handle_row_event(event);
|
|
|
|
}
|
|
|
|
if (event.target.attributes['data-col-id'] !== undefined) {
|
|
|
|
this.handle_col_event(event);
|
2013-11-14 16:31:07 +00:00
|
|
|
}
|
2013-11-14 10:34:46 +00:00
|
|
|
},
|
2013-11-18 14:19:55 +00:00
|
|
|
|
2013-11-14 10:34:46 +00:00
|
|
|
'click a.field-selection' : function (event) {
|
2013-11-19 09:20:53 +00:00
|
|
|
var id,
|
|
|
|
field_id = event.target.attributes['data-field-id'].nodeValue;
|
2013-11-14 10:34:46 +00:00
|
|
|
event.preventDefault();
|
|
|
|
this.dropdown.remove();
|
2013-11-19 09:20:53 +00:00
|
|
|
if (event.target.attributes['data-row-id'] !== undefined) {
|
2013-11-20 11:08:21 +00:00
|
|
|
id = event.target.attributes['data-row-id'].nodeValue;
|
2013-11-19 09:20:53 +00:00
|
|
|
this.expand_row(id, field_id);
|
|
|
|
}
|
|
|
|
if (event.target.attributes['data-col-id'] !== undefined) {
|
2013-11-20 11:08:21 +00:00
|
|
|
id = event.target.attributes['data-col-id'].nodeValue;
|
2013-11-19 09:20:53 +00:00
|
|
|
this.expand_col(id, field_id);
|
|
|
|
}
|
2013-11-13 15:47:31 +00:00
|
|
|
},
|
|
|
|
},
|
2013-11-18 13:07:56 +00:00
|
|
|
|
2013-11-18 15:26:20 +00:00
|
|
|
handle_row_event: function (event) {
|
|
|
|
var row_id = event.target.attributes['data-row-id'].nodeValue,
|
|
|
|
row = this.get_row(row_id);
|
|
|
|
|
|
|
|
if (row.expanded) {
|
|
|
|
this.fold_row(row_id);
|
|
|
|
} else {
|
|
|
|
if (row.path.length < this.data.row_groupby.length) {
|
|
|
|
var field_to_expand = this.data.row_groupby[row.path.length];
|
|
|
|
this.expand_row(row_id, field_to_expand);
|
|
|
|
} else {
|
2013-11-19 09:20:53 +00:00
|
|
|
this.display_dropdown({row_id:row_id,
|
|
|
|
target: $(event.target),
|
2013-11-20 13:15:43 +00:00
|
|
|
x: event.pageX,
|
2013-11-19 09:20:53 +00:00
|
|
|
y: event.pageY});
|
2013-11-18 15:26:20 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
handle_col_event: function (event) {
|
2013-11-19 09:20:53 +00:00
|
|
|
var col_id = event.target.attributes['data-col-id'].nodeValue,
|
|
|
|
col = this.get_col(col_id);
|
|
|
|
|
|
|
|
if (col.expanded) {
|
|
|
|
this.fold_col(col_id);
|
|
|
|
} else {
|
|
|
|
if (col.path.length < this.data.col_groupby.length) {
|
|
|
|
var field_to_expand = this.data.col_groupby[col.path.length];
|
|
|
|
this.expand_col(col_id, field_to_expand);
|
|
|
|
} else {
|
|
|
|
this.display_dropdown({col_id: col_id,
|
|
|
|
target: $(event.target),
|
|
|
|
x: event.pageX,
|
|
|
|
y: event.pageY});
|
|
|
|
}
|
|
|
|
}
|
2013-11-18 15:26:20 +00:00
|
|
|
},
|
|
|
|
|
2013-11-18 12:53:20 +00:00
|
|
|
init: function (data) {
|
|
|
|
this.data = data;
|
|
|
|
},
|
2013-11-13 15:47:31 +00:00
|
|
|
|
2013-11-18 12:53:20 +00:00
|
|
|
start: function () {
|
2013-11-18 13:07:56 +00:00
|
|
|
this.draw(true);
|
2013-11-14 15:33:48 +00:00
|
|
|
},
|
|
|
|
|
2013-11-18 13:07:56 +00:00
|
|
|
draw: function (load_data) {
|
2013-11-18 12:53:20 +00:00
|
|
|
var self = this;
|
|
|
|
|
2013-11-21 09:07:19 +00:00
|
|
|
if (load_data) {
|
2013-11-20 14:19:14 +00:00
|
|
|
var view_fields = this.data.row_groupby.concat(this.data.measure, this.data.col_groupby);
|
|
|
|
query_groups_data(this.data.model, view_fields, this.data.domain, this.data.col_groupby, this.data.row_groupby[0])
|
2013-11-18 13:07:56 +00:00
|
|
|
.then(function (groups) {
|
|
|
|
self.data.groups = groups;
|
|
|
|
return self.get_groups([]);
|
|
|
|
}).then(function (total) {
|
2013-11-21 09:07:19 +00:00
|
|
|
total[0].path = [];
|
2013-11-20 14:19:14 +00:00
|
|
|
self.data.total = [total];
|
2013-11-18 13:07:56 +00:00
|
|
|
self.build_table();
|
|
|
|
self.draw(false);
|
|
|
|
});
|
|
|
|
} else {
|
|
|
|
this.$el.empty();
|
2013-11-18 12:53:20 +00:00
|
|
|
|
2013-11-19 14:52:33 +00:00
|
|
|
this.draw_top_headers();
|
2013-11-18 13:07:56 +00:00
|
|
|
|
|
|
|
_.each(this.rows, function (row) {
|
|
|
|
self.$el.append(row.html);
|
|
|
|
});
|
|
|
|
}
|
2013-11-13 15:47:31 +00:00
|
|
|
},
|
2013-11-12 11:31:34 +00:00
|
|
|
|
2013-11-18 12:53:20 +00:00
|
|
|
show: function () {
|
|
|
|
this.$el.css('display', 'block');
|
|
|
|
},
|
|
|
|
|
|
|
|
hide: function () {
|
|
|
|
this.$el.css('display', 'none');
|
|
|
|
},
|
|
|
|
|
2013-11-19 09:20:53 +00:00
|
|
|
display_dropdown: function (options) {
|
2013-11-18 14:19:55 +00:00
|
|
|
var self = this,
|
|
|
|
already_grouped = self.data.row_groupby.concat(self.data.col_groupby),
|
|
|
|
possible_groups = _.difference(self.data.important_fields, already_grouped),
|
|
|
|
dropdown_options = {
|
|
|
|
fields: _.map(possible_groups, function (field) {
|
|
|
|
return {id: field, value: self.get_descr(field)};
|
2013-11-19 09:20:53 +00:00
|
|
|
})};
|
|
|
|
if (options.row_id) {
|
|
|
|
dropdown_options.row_id= options.row_id;
|
|
|
|
} else {
|
|
|
|
dropdown_options.col_id = options.col_id;
|
|
|
|
}
|
|
|
|
|
2013-11-18 14:19:55 +00:00
|
|
|
this.dropdown = $(QWeb.render('field_selection', dropdown_options));
|
2013-11-19 09:20:53 +00:00
|
|
|
options.target.after(this.dropdown);
|
2013-11-18 14:19:55 +00:00
|
|
|
this.dropdown.css({position:'absolute',
|
2013-11-19 09:20:53 +00:00
|
|
|
left:options.x,
|
|
|
|
top:options.y});
|
2013-11-18 14:19:55 +00:00
|
|
|
$('.field-selection').next('.dropdown-menu').toggle();
|
|
|
|
},
|
|
|
|
|
2013-11-18 12:53:20 +00:00
|
|
|
build_table: function () {
|
|
|
|
var self = this;
|
2013-11-20 11:17:28 +00:00
|
|
|
this.rows = [];
|
|
|
|
|
2013-11-18 12:53:20 +00:00
|
|
|
|
2013-11-18 15:26:20 +00:00
|
|
|
var col_id = this.generate_id();
|
2013-11-18 12:53:20 +00:00
|
|
|
|
2013-11-18 15:26:20 +00:00
|
|
|
this.cols= [{
|
2013-11-19 09:20:53 +00:00
|
|
|
id: col_id,
|
2013-11-18 15:26:20 +00:00
|
|
|
path: [],
|
|
|
|
value: this.data.measure_label,
|
|
|
|
expanded: false,
|
|
|
|
parent: null,
|
|
|
|
children: [],
|
|
|
|
cells: [], // a cell is {td:<jquery td>, row_id:<some id>}
|
|
|
|
domain: this.data.domain,
|
|
|
|
}];
|
|
|
|
|
2013-11-19 14:52:33 +00:00
|
|
|
self.make_top_headers();
|
|
|
|
|
2013-11-18 12:53:20 +00:00
|
|
|
var main_row = this.make_row(this.data.total[0]);
|
|
|
|
|
|
|
|
_.each(this.data.groups, function (group) {
|
|
|
|
self.make_row(group, main_row.id);
|
2013-11-14 10:34:46 +00:00
|
|
|
});
|
|
|
|
},
|
|
|
|
|
2013-11-18 12:53:20 +00:00
|
|
|
get_descr: function (field_id) {
|
|
|
|
return this.data.fields[field_id].string;
|
|
|
|
},
|
2013-11-14 13:17:47 +00:00
|
|
|
|
2013-11-18 12:53:20 +00:00
|
|
|
get_groups: function (groupby) {
|
|
|
|
var view_fields = this.data.row_groupby.concat(this.data.measure, this.data.col_groupby);
|
|
|
|
return query_groups(this.data.model, view_fields, this.data.domain, groupby);
|
2013-11-14 13:17:47 +00:00
|
|
|
},
|
|
|
|
|
2013-11-19 14:52:33 +00:00
|
|
|
make_top_headers : function () {
|
2013-11-20 11:08:21 +00:00
|
|
|
var self = this,
|
|
|
|
header;
|
2013-11-19 14:52:33 +00:00
|
|
|
|
2013-11-20 11:08:21 +00:00
|
|
|
function partition (columns) {
|
|
|
|
return _.reduce(columns, function (partial, col) {
|
|
|
|
if (partial.length === 0) return [[col]];
|
|
|
|
if (col.path.length > _.first(_.last(partial)).path.length) {
|
|
|
|
_.last(partial).push(col);
|
|
|
|
} else {
|
|
|
|
partial.push([col]);
|
|
|
|
}
|
|
|
|
return partial;
|
|
|
|
}, []);
|
|
|
|
}
|
2013-11-19 14:52:33 +00:00
|
|
|
|
2013-11-20 11:08:21 +00:00
|
|
|
function side_by_side(blocks) {
|
|
|
|
var result = _.zip.apply(_,blocks);
|
|
|
|
result = _.map(result, function(line) {return _.compact(_.flatten(line))});
|
|
|
|
return result;
|
|
|
|
}
|
2013-11-19 14:52:33 +00:00
|
|
|
|
2013-11-20 11:08:21 +00:00
|
|
|
function make_header_cell(col, span) {
|
|
|
|
var options = {
|
|
|
|
is_border:true,
|
|
|
|
foldable:true,
|
|
|
|
row_span: (span === undefined) ? 1 : span,
|
|
|
|
col_id: col.id,
|
|
|
|
};
|
|
|
|
var result = self.make_cell(col.value, options);
|
2013-11-20 13:07:48 +00:00
|
|
|
if (col.expanded) {
|
|
|
|
result.find('.icon-plus-sign')
|
|
|
|
.removeClass('icon-plus-sign')
|
|
|
|
.addClass('icon-minus-sign');
|
|
|
|
}
|
2013-11-20 11:08:21 +00:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
function calculate_width(cols) {
|
|
|
|
if (cols.length === 1) {
|
|
|
|
return 1;
|
2013-11-19 14:52:33 +00:00
|
|
|
}
|
2013-11-20 11:08:21 +00:00
|
|
|
var p = partition(_.rest(cols));
|
|
|
|
return _.reduce(p, function(x, y){ return x + calculate_width(y); }, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
function make_header_cells(cols, height) {
|
|
|
|
var p = partition(cols);
|
|
|
|
if ((p.length === 1) && (p[0].length === 1)) {
|
|
|
|
var result = [[make_header_cell(cols[0], height)]];
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
if ((p.length === 1) && (p[0].length > 1)) {
|
|
|
|
var cell = make_header_cell(p[0][0]);
|
|
|
|
cell.attr('colspan', calculate_width(cols));
|
|
|
|
return [[cell]].concat(make_header_cells(_.rest(cols), height - 1));
|
|
|
|
}
|
|
|
|
if (p.length > 1) {
|
|
|
|
return side_by_side(_.map(p, function (group) {
|
|
|
|
return make_header_cells(group, height);
|
|
|
|
}));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (this.cols.length === 1) {
|
|
|
|
header = $('<tr></tr>');
|
|
|
|
header.append(this.make_cell('', {is_border:true}));
|
|
|
|
header.append(this.make_cell(this.cols[0].value,
|
|
|
|
{is_border:true, foldable:true, col_id:this.cols[0].id}));
|
|
|
|
header.addClass('graph_top');
|
|
|
|
this.headers = [header];
|
|
|
|
} else {
|
|
|
|
var height = _.max(_.map(self.cols, function(g) {return g.path.length;}));
|
|
|
|
var header_rows = make_header_cells(_.rest(this.cols), height);
|
|
|
|
|
|
|
|
header_rows[0].splice(0,0,self.make_cell('', {is_border:true, }).attr('rowspan', height))
|
|
|
|
self.headers = [];
|
|
|
|
_.each(header_rows, function (cells) {
|
|
|
|
header = $('<tr></tr>');
|
|
|
|
header.append(cells);
|
|
|
|
header.addClass('graph_top');
|
|
|
|
self.headers.push(header);
|
|
|
|
});
|
|
|
|
}
|
2013-11-19 14:52:33 +00:00
|
|
|
},
|
|
|
|
|
|
|
|
draw_top_headers: function () {
|
|
|
|
var self = this;
|
|
|
|
$("tr.graph_top").remove();
|
2013-11-20 11:08:21 +00:00
|
|
|
_.each(this.headers.reverse(), function (header) {
|
2013-11-19 14:52:33 +00:00
|
|
|
self.$el.prepend(header);
|
|
|
|
});
|
|
|
|
|
|
|
|
},
|
|
|
|
|
2013-11-21 09:07:19 +00:00
|
|
|
make_row: function (groups, parent_id) {
|
|
|
|
var self = this,
|
|
|
|
path,
|
2013-11-18 12:53:20 +00:00
|
|
|
value,
|
|
|
|
expanded,
|
|
|
|
domain,
|
|
|
|
parent,
|
|
|
|
has_parent = (parent_id !== undefined),
|
|
|
|
row_id = this.generate_id();
|
|
|
|
|
2013-11-14 15:33:48 +00:00
|
|
|
if (has_parent) {
|
2013-11-18 12:53:20 +00:00
|
|
|
parent = this.get_row(parent_id);
|
2013-11-21 09:07:19 +00:00
|
|
|
path = parent.path.concat(groups[0].attributes.value[1]);
|
|
|
|
value = groups[0].attributes.value[1];
|
2013-11-18 12:53:20 +00:00
|
|
|
expanded = false;
|
|
|
|
parent.children.push(row_id);
|
2013-11-21 09:07:19 +00:00
|
|
|
domain = groups[0].model._domain;
|
2013-11-14 15:33:48 +00:00
|
|
|
} else {
|
2013-11-18 12:53:20 +00:00
|
|
|
parent = null;
|
2013-11-14 15:33:48 +00:00
|
|
|
path = [];
|
2013-11-18 12:53:20 +00:00
|
|
|
value = 'Total';
|
|
|
|
expanded = true;
|
|
|
|
domain = this.data.domain;
|
2013-11-14 15:33:48 +00:00
|
|
|
}
|
2013-11-14 13:17:47 +00:00
|
|
|
|
|
|
|
var jquery_row = $('<tr></tr>');
|
|
|
|
|
2013-11-21 09:07:19 +00:00
|
|
|
var header = self.make_cell(value, {is_border:true, indent: path.length, foldable:true, row_id: row_id});
|
|
|
|
jquery_row.append(header);
|
|
|
|
|
|
|
|
var cell;
|
2013-11-18 15:26:20 +00:00
|
|
|
|
|
|
|
_.each(this.cols, function (col) {
|
2013-11-21 09:07:19 +00:00
|
|
|
var element = _.find(groups, function (group) {
|
|
|
|
return _.isEqual(_.rest(group.path), col.path);
|
|
|
|
});
|
|
|
|
if (element === undefined) {
|
|
|
|
cell = self.make_cell('');
|
|
|
|
} else {
|
|
|
|
cell = self.make_cell(element.attributes.aggregates[self.data.measure]);
|
|
|
|
}
|
|
|
|
if (col.expanded) {
|
|
|
|
cell.css('display', 'none');
|
|
|
|
}
|
|
|
|
col.cells.push({td:cell, row_id:row_id});
|
|
|
|
jquery_row.append(cell);
|
2013-11-18 15:26:20 +00:00
|
|
|
});
|
2013-11-14 13:17:47 +00:00
|
|
|
|
2013-11-20 13:07:48 +00:00
|
|
|
if (!has_parent) {
|
|
|
|
header.find('.icon-plus-sign')
|
|
|
|
.removeClass('icon-plus-sign')
|
|
|
|
.addClass('icon-minus-sign');
|
|
|
|
}
|
|
|
|
|
2013-11-14 13:17:47 +00:00
|
|
|
var row = {
|
|
|
|
id: row_id,
|
|
|
|
path: path,
|
2013-11-14 15:33:48 +00:00
|
|
|
value: value,
|
2013-11-18 12:53:20 +00:00
|
|
|
expanded: expanded,
|
2013-11-14 13:17:47 +00:00
|
|
|
parent: parent_id,
|
|
|
|
children: [],
|
2013-11-18 12:53:20 +00:00
|
|
|
html: jquery_row,
|
|
|
|
domain: domain,
|
2013-11-14 13:17:47 +00:00
|
|
|
};
|
2013-11-18 12:53:20 +00:00
|
|
|
this.rows.push(row); // to do, insert it properly, after all childs of parent
|
|
|
|
return row;
|
|
|
|
},
|
2013-11-14 13:17:47 +00:00
|
|
|
|
2013-11-18 12:53:20 +00:00
|
|
|
generate_id: function () {
|
2013-11-18 15:26:20 +00:00
|
|
|
this.id_seed += 1;
|
|
|
|
return this.id_seed - 1;
|
2013-11-18 12:53:20 +00:00
|
|
|
},
|
|
|
|
|
|
|
|
get_row: function (id) {
|
|
|
|
return _.find(this.rows, function(row) {
|
|
|
|
return (row.id == id);
|
|
|
|
});
|
|
|
|
},
|
|
|
|
|
2013-11-18 15:26:20 +00:00
|
|
|
get_col: function (id) {
|
|
|
|
return _.find(this.cols, function(col) {
|
|
|
|
return (col.id == id);
|
|
|
|
});
|
|
|
|
},
|
|
|
|
|
2013-11-18 12:53:20 +00:00
|
|
|
make_cell: function (content, options) {
|
|
|
|
options = _.extend({is_border: false, indent:0, foldable:false}, options);
|
2013-11-18 15:26:20 +00:00
|
|
|
content = (content !== undefined) ? content : 'Undefined';
|
2013-11-18 12:53:20 +00:00
|
|
|
|
|
|
|
var cell = $('<td></td>');
|
|
|
|
if (options.is_border) cell.addClass('graph_border');
|
2013-11-20 11:08:21 +00:00
|
|
|
if (options.row_span) cell.attr('rowspan', options.row_span);
|
|
|
|
if (options.col_span) cell.attr('rowspan', options.col_span);
|
2013-11-18 12:53:20 +00:00
|
|
|
_.each(_.range(options.indent), function () {
|
|
|
|
cell.prepend($('<span/>', {class:'web_graph_indent'}));
|
|
|
|
});
|
|
|
|
|
|
|
|
if (options.foldable) {
|
2013-11-18 15:26:20 +00:00
|
|
|
var attrs = {class:'icon-plus-sign web_graph_click', href:'#'};
|
|
|
|
if (options.row_id !== undefined) attrs['data-row-id'] = options.row_id;
|
|
|
|
if (options.col_id !== undefined) attrs['data-col-id'] = options.col_id;
|
|
|
|
var plus = $('<span/>', attrs);
|
2013-11-18 12:53:20 +00:00
|
|
|
plus.append(' ');
|
|
|
|
plus.append(content);
|
|
|
|
cell.append(plus);
|
|
|
|
} else {
|
|
|
|
cell.append(content);
|
2013-11-14 13:17:47 +00:00
|
|
|
}
|
2013-11-18 12:53:20 +00:00
|
|
|
return cell;
|
2013-11-14 10:34:46 +00:00
|
|
|
},
|
|
|
|
|
|
|
|
expand_row: function (row_id, field_id) {
|
2013-11-14 13:17:47 +00:00
|
|
|
var self = this;
|
2013-11-14 10:34:46 +00:00
|
|
|
var row = this.get_row(row_id);
|
2013-11-15 09:24:11 +00:00
|
|
|
|
2013-11-18 12:53:20 +00:00
|
|
|
if (row.path.length == this.data.row_groupby.length) {
|
|
|
|
this.data.row_groupby.push(field_id);
|
2013-11-15 09:24:11 +00:00
|
|
|
}
|
2013-11-18 12:53:20 +00:00
|
|
|
row.expanded = true;
|
|
|
|
row.html.find('.icon-plus-sign')
|
|
|
|
.removeClass('icon-plus-sign')
|
|
|
|
.addClass('icon-minus-sign');
|
2013-11-14 15:33:48 +00:00
|
|
|
|
2013-11-18 12:53:20 +00:00
|
|
|
var visible_fields = this.data.row_groupby.concat(this.data.col_groupby, this.data.measure);
|
2013-11-20 14:19:14 +00:00
|
|
|
query_groups_data(this.data.model, visible_fields, row.domain, this.data.col_groupby, field_id)
|
2013-11-19 13:20:24 +00:00
|
|
|
.then(function (groups) {
|
|
|
|
_.each(groups.reverse(), function (group) {
|
|
|
|
var new_row = self.make_row(group, row_id);
|
2013-11-18 12:53:20 +00:00
|
|
|
row.html.after(new_row.html);
|
2013-11-14 13:17:47 +00:00
|
|
|
});
|
2013-11-14 10:34:46 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
},
|
|
|
|
|
2013-11-19 09:20:53 +00:00
|
|
|
expand_col: function (col_id, field_id) {
|
2013-11-19 13:20:24 +00:00
|
|
|
var self = this;
|
|
|
|
var col = this.get_col(col_id);
|
|
|
|
|
|
|
|
if (col.path.length == this.data.col_groupby.length) {
|
|
|
|
this.data.col_groupby.push(field_id);
|
|
|
|
}
|
|
|
|
col.expanded = true;
|
|
|
|
|
|
|
|
var visible_fields = this.data.row_groupby.concat(this.data.col_groupby, this.data.measure);
|
|
|
|
query_groups_data(this.data.model, visible_fields, col.domain, this.data.row_groupby, field_id)
|
|
|
|
.then(function (groups) {
|
|
|
|
_.each(groups, function (group) {
|
|
|
|
var new_col = {
|
|
|
|
id: self.generate_id(),
|
2013-11-20 11:08:21 +00:00
|
|
|
path: col.path.concat(group[0].attributes.value[1]),
|
2013-11-19 13:20:24 +00:00
|
|
|
value: group[0].attributes.value[1],
|
|
|
|
expanded: false,
|
|
|
|
parent: col_id,
|
|
|
|
children: [],
|
|
|
|
cells: [], // a cell is {td:<jquery td>, row_id:<some id>}
|
|
|
|
domain: group[0].model._domain,
|
|
|
|
};
|
|
|
|
col.children.push(new_col.id);
|
2013-11-20 11:08:21 +00:00
|
|
|
insertAfter(self.cols, col, new_col)
|
2013-11-19 13:20:24 +00:00
|
|
|
_.each(col.cells, function (cell) {
|
|
|
|
var col_path = self.get_row(cell.row_id).path;
|
|
|
|
|
|
|
|
var datapt = _.find(group, function (g) {
|
|
|
|
return _.isEqual(g.path.slice(1), col_path);
|
|
|
|
});
|
|
|
|
|
|
|
|
var value;
|
|
|
|
if (datapt === undefined) {
|
|
|
|
value = '';
|
|
|
|
} else {
|
|
|
|
value = datapt.attributes.aggregates[self.data.measure];
|
|
|
|
}
|
|
|
|
var new_cell = {
|
|
|
|
row_id: cell.row_id,
|
|
|
|
td: self.make_cell(value)
|
|
|
|
};
|
|
|
|
new_col.cells.push(new_cell);
|
|
|
|
cell.td.after(new_cell.td);
|
|
|
|
cell.td.css('display','none');
|
|
|
|
});
|
|
|
|
|
|
|
|
});
|
2013-11-19 14:52:33 +00:00
|
|
|
self.make_top_headers();
|
|
|
|
self.draw_top_headers();
|
2013-11-19 13:20:24 +00:00
|
|
|
});
|
2013-11-19 09:20:53 +00:00
|
|
|
},
|
|
|
|
|
2013-11-14 16:31:07 +00:00
|
|
|
fold_row: function (row_id) {
|
2013-11-15 08:50:37 +00:00
|
|
|
var self = this;
|
|
|
|
var row = this.get_row(row_id);
|
|
|
|
|
|
|
|
_.each(row.children, function (child_row) {
|
2013-11-15 11:19:32 +00:00
|
|
|
self.remove_row(child_row);
|
2013-11-15 08:50:37 +00:00
|
|
|
});
|
|
|
|
row.children = [];
|
|
|
|
|
|
|
|
row.expanded = false;
|
2013-11-18 12:53:20 +00:00
|
|
|
row.html.find('.icon-minus-sign')
|
2013-11-15 08:50:37 +00:00
|
|
|
.removeClass('icon-minus-sign')
|
2013-11-15 11:19:32 +00:00
|
|
|
.addClass('icon-plus-sign');
|
2013-11-15 08:50:37 +00:00
|
|
|
|
2013-11-15 11:19:32 +00:00
|
|
|
var fold_levels = _.map(self.rows, function(g) {return g.path.length;});
|
2013-11-20 11:08:21 +00:00
|
|
|
var new_groupby_length = _.max(fold_levels);
|
2013-11-15 11:19:32 +00:00
|
|
|
|
2013-11-18 12:53:20 +00:00
|
|
|
this.data.row_groupby.splice(new_groupby_length);
|
2013-11-15 08:50:37 +00:00
|
|
|
},
|
|
|
|
|
|
|
|
remove_row: function (row_id) {
|
|
|
|
var self = this;
|
|
|
|
var row = this.get_row(row_id);
|
|
|
|
|
|
|
|
_.each(row.children, function (child_row) {
|
|
|
|
self.remove_row(child_row);
|
|
|
|
});
|
2013-11-14 16:31:07 +00:00
|
|
|
|
2013-11-18 12:53:20 +00:00
|
|
|
row.html.remove();
|
2013-11-15 11:19:32 +00:00
|
|
|
removeFromArray(this.rows, row);
|
2013-11-18 15:26:20 +00:00
|
|
|
|
|
|
|
_.each(this.cols, function (col) {
|
|
|
|
col.cells = _.filter(col.cells, function (cell) {
|
|
|
|
return cell.row_id !== row_id;
|
|
|
|
});
|
|
|
|
});
|
2013-11-14 16:31:07 +00:00
|
|
|
},
|
|
|
|
|
2013-11-20 12:46:32 +00:00
|
|
|
fold_col: function (col_id) {
|
|
|
|
var self = this;
|
|
|
|
var col = this.get_col(col_id);
|
|
|
|
|
|
|
|
_.each(col.children, function (child_col) {
|
|
|
|
self.remove_col(child_col);
|
|
|
|
});
|
|
|
|
col.children = [];
|
|
|
|
|
|
|
|
_.each(col.cells, function (cell) {
|
|
|
|
cell.td.css('display','table-cell');
|
|
|
|
});
|
|
|
|
col.expanded = false;
|
|
|
|
// row.html.find('.icon-minus-sign')
|
|
|
|
// .removeClass('icon-minus-sign')
|
|
|
|
// .addClass('icon-plus-sign');
|
|
|
|
|
|
|
|
var fold_levels = _.map(self.cols, function(g) {return g.path.length;});
|
|
|
|
var new_groupby_length = _.max(fold_levels);
|
|
|
|
|
|
|
|
this.data.col_groupby.splice(new_groupby_length);
|
|
|
|
this.make_top_headers();
|
|
|
|
this.draw_top_headers();
|
|
|
|
|
|
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
remove_col: function (col_id) {
|
|
|
|
var self = this;
|
|
|
|
var col = this.get_col(col_id);
|
|
|
|
|
|
|
|
_.each(col.children, function (child_col) {
|
|
|
|
self.remove_col(child_col);
|
|
|
|
});
|
|
|
|
|
|
|
|
_.each(col.cells, function (cell) {
|
|
|
|
cell.td.remove();
|
|
|
|
});
|
|
|
|
// row.html.remove();
|
|
|
|
removeFromArray(this.cols, col);
|
|
|
|
|
|
|
|
// _.each(this.cols, function (col) {
|
|
|
|
// col.cells = _.filter(col.cells, function (cell) {
|
|
|
|
// return cell.row_id !== row_id;
|
|
|
|
// });
|
|
|
|
// });
|
|
|
|
},
|
|
|
|
|
|
|
|
|
2013-11-08 13:08:06 +00:00
|
|
|
});
|
|
|
|
|
2011-04-15 06:42:41 +00:00
|
|
|
};
|