[MERGE] Kanban refactoring

lp bug: https://launchpad.net/bugs/883552 fixed

bzr revid: fme@openerp.com-20111107104420-gj1zgoxasun8rk19
This commit is contained in:
Fabien Meghazi 2011-11-07 11:44:20 +01:00
commit 35a595b272
3 changed files with 481 additions and 427 deletions

View File

@ -1,37 +1,71 @@
.openerp .oe_kanban_view .oe_column {
width: 100%;
}
.openerp .oe_vertical_text {
writing-mode:tb-rl;
-webkit-transform:rotate(90deg);
-moz-transform:rotate(90deg);
-o-transform: rotate(90deg);
-ms-transform: rotate(90deg);
transform: rotate(90deg);
display:block;
width:30px;
height:20px;
align:center;
font-size:24px;
white-space: nowrap;
}
.openerp .oe_kanban_view .ui-sortable-placeholder {
border: 1px dotted black;
visibility: visible !important;
height: 60px !important;
}
.openerp .oe_kanban_group_header {
position: relative;
}
.openerp .oe_kanban_group_folded {
padding: 0 5px 0 5px;
}
.openerp .oe_kanban_group_folded .oe_kanban_group_title,
.openerp .oe_kanban_group_folded .oe_kanban_aggregates {
display: none;
}
.openerp .oe_kanban_group_folded .oe_kanban_group_title_vertical {
display: block;
}
.openerp .oe_kanban_view .oe_column_heading {
.openerp .oe_kanban_group_title {
color: #000000;
font-size: 130%;
font-weight: bold;
}
.openerp .oe_kanban_view .fold-columns-icon {
.openerp .oe_kanban_group_title_undefined {
color: #666666;
}
.openerp .oe_kanban_group_title_vertical {
writing-mode: tb-rl;
-webkit-transform: rotate(90deg);
-moz-transform: rotate(90deg);
-o-transform: rotate(90deg);
-ms-transform: rotate(90deg);
transform: rotate(90deg);
width: 30px;
height: 20px;
align: center;
font-size: 24px;
white-space: nowrap;
display: none;
position: absolute;
top: 10px;
}
.openerp .oe_kanban_fold_icon {
cursor: pointer;
float: left;
padding: 2px 2px 0 0;
width: 16px;
height: 16px;
background: url(/web_kanban/static/src/img/minus-icon.png) no-repeat;
}
.openerp .oe_kanban_group_folded .oe_kanban_fold_icon {
background: url(/web_kanban/static/src/img/plus-icon.png) no-repeat;
}
.openerp ul.oe_kanban_aggregates {
padding: 0;
margin: 0 0 0 22px;
}
.openerp ul.oe_kanban_aggregates li {
list-style: circle;
font-style: italic;
}
.openerp ul.oe_kanban_aggregates span {
text-decoration: underline;
}
.openerp .oe_kanban_action_button {
height: 22px;
margin: 0;

View File

@ -1,38 +1,59 @@
openerp.web_kanban = function (openerp) {
var _t = openerp.web._t;
var QWeb = openerp.web.qweb;
QWeb.add_template('/web_kanban/static/src/xml/web_kanban.xml');
openerp.web.views.add('kanban', 'openerp.web_kanban.KanbanView');
openerp.web_kanban.KanbanView = openerp.web.View.extend({
template: "KanbanView",
default_nr_columns: 3,
init: function (parent, dataset, view_id, options) {
this._super(parent);
this.set_default_options(options);
this.dataset = dataset;
this.model = dataset.model;
this.view_id = view_id;
this.fields_view = {};
this.group_by = [];
this.source_index = {};
this.all_display_data = false;
this.fields_keys = [];
this.group_by = null;
this.state = {
groups : {},
records : {}
};
this.groups = [];
this.form_dialog = new openerp.web.FormDialog(this, {}, this.options.action_views_ids.form, dataset).start();
this.form_dialog.on_form_dialog_saved.add_last(this.do_reload);
this.aggregates = {};
this.qweb = new QWeb2.Engine();
this.qweb.debug = (window.location.search.indexOf('?debug') !== -1);
this.aggregates = {};
this.NO_OF_COLUMNS = 3;
this.form_dialog = new openerp.web.FormDialog(this, {}, this.options.action_views_ids.form, dataset).start();
this.form_dialog.on_form_dialog_saved.add_last(this.on_record_saved);
this.qweb.default_dict = {
'_' : _,
'_t' : _t
}
this.has_been_loaded = $.Deferred();
this.search_domain = this.search_context = this.search_group_by = null;
this.currently_dragging = {};
},
start: function() {
this._super();
return this.rpc("/web/view/load", {"model": this.model, "view_id": this.view_id, "view_type": "kanban"}, this.on_loaded);
this.$element.find('button.oe_kanban_button_new').click(this.do_add_record);
this.$groups = this.$element.find('.oe_kanban_groups tr');
var context = new openerp.web.CompoundContext(this.dataset.get_context());
return this.rpc('/web/view/load', {
'model': this.dataset.model,
'view_id': this.view_id,
'view_type': 'kanban',
context: context
}, this.on_loaded);
},
on_loaded: function(data) {
var self = this;
this.fields_view = data;
this.fields_keys = _.keys(this.fields_view.fields);
this.add_qweb_template();
this.has_been_loaded.resolve();
},
add_qweb_template: function() {
var group_operator = ["avg", "max", "min", "sum", "count"]
var group_operator = ['avg', 'max', 'min', 'sum', 'count']
for (var i=0, ii=this.fields_view.arch.children.length; i < ii; i++) {
var child = this.fields_view.arch.children[i];
if (child.tag === "field") {
@ -50,50 +71,6 @@ openerp.web_kanban.KanbanView = openerp.web.View.extend({
}
}
},
get_qweb_context: function(record) {
return {
record: this.do_transform_record(record),
kanban_color: _.bind(this.kanban_color, this),
kanban_gravatar: _.bind(this.kanban_gravatar, this),
kanban_image: _.bind(this.kanban_image, this),
kanban_text_ellipsis: _.bind(this.kanban_text_ellipsis, this),
'_' : _
}
},
kanban_color: function(variable) {
var number_of_color_schemes = 10,
index = 0;
switch (typeof(variable)) {
case 'string':
for (var i=0, ii=variable.length; i<ii; i++) {
index += variable.charCodeAt(i);
}
break;
case 'number':
index = Math.round(variable);
break;
default:
return '';
}
var color = (index % number_of_color_schemes);
return 'oe_kanban_color_' + color;
},
kanban_gravatar: function(email, size) {
size = size || 22;
var email_md5 = $.md5(email);
return 'http://www.gravatar.com/avatar/' + email_md5 + '.png?s=' + size;
},
kanban_image: function(model, field, id) {
id = id || '';
return '/web/binary/image?session_id=' + this.session.session_id + '&model=' + model + '&field=' + field + '&id=' + id;
},
kanban_text_ellipsis: function(s, size) {
size = size || 160;
if (!s) {
return '';
}
return s.substr(0, size) + '...';
},
transform_qweb_template: function(node) {
var qweb_prefix = QWeb.prefix;
switch (node.tag) {
@ -145,358 +122,391 @@ openerp.web_kanban.KanbanView = openerp.web.View.extend({
}
}
},
on_show_data: function() {
var self = this;
if (!this.group_by.length) {
this.do_record_group();
}
this.$element.html(QWeb.render("KanbanView", {"data": self.all_display_data}));
this.on_reload_kanban();
this.$element.find(".oe_vertical_text").hide();
var drag_handel = false;
if (this.$element.find(".oe_kanban_draghandle").length > 0) {
drag_handel = ".oe_kanban_draghandle";
}
if (!this.group_by.length) {
drag_handel = true;
}
this.$element.find(".oe_column").sortable({
connectWith: ".oe_column",
handle : drag_handel,
start: function(event, ui) {
self.source_index['index'] = ui.item.index();
self.source_index['column'] = ui.item.parent().attr('id');
},
stop: self.on_receive_record,
scroll: false
});
this.$element.find('button.oe_kanban_button_new').click(this.do_add_record);
this.$element.find(".fold-columns-icon").click(function(event) {
self.do_fold_unfold_columns(event, this.id);
});
},
do_fold_unfold_columns: function(event, element_id) {
var column_id = "column_" + element_id;
var column_element = this.$element.find("#" + column_id + " .oe_fold_column");
if (column_element.is(":hidden")) {
this.$element.find("#" + column_id).find("img.fold-columns-icon").attr('src', '/web_kanban/static/src/img/minus-icon.png');
column_element.show();
this.$element.find("#" + column_id + ".oe_table_column").css("width",Math.round(99 / this.all_display_data.length) + "%");
this.$element.find("#" + column_id + ".oe_vertical_text").hide();
}
else{
this.$element.find("#" + column_id).find("img.fold-columns-icon").attr('src', '/web_kanban/static/src/img/plus-icon.png');
column_element.hide();
this.$element.find("#" + column_id + ".oe_table_column").css("width","0.5%");
this.$element.find("#" + column_id + ".oe_vertical_text").show();
}
},
do_record_group: function() {
if (this.NO_OF_COLUMNS && this.all_display_data.length > 0) {
var records = this.all_display_data[0].records;
var record_per_group = Math.round((records).length / this.NO_OF_COLUMNS);
this.all_display_data = [];
for (var i=0, ii=this.NO_OF_COLUMNS; i < ii; i++) {
this.all_display_data.push({'records': records.slice(0,record_per_group), 'value':i, 'header' : false, 'ids':[]});
records.splice(0,record_per_group);
}
}
},
on_button_click: function (button_attrs, record_id) {
this.on_execute_button_click(this.dataset, button_attrs, record_id);
},
do_add_record: function() {
this.dataset.index = null;
this.do_switch_view('form');
},
do_edit_record: function(record_id) {
do_search: function(domain, context, group_by) {
var self = this;
this.form_dialog.select_id(record_id).then(function() {
self.form_dialog.open();
this.search_domain = domain;
this.search_context = context;
this.search_group_by = group_by;
$.when(this.has_been_loaded).then(function() {
self.group_by = group_by.length ? group_by[0] : self.fields_view.arch.attrs.default_group_by;
self.datagroup = new openerp.web.DataGroup(self, self.dataset.model, domain, context, self.group_by ? [self.group_by] : []);
self.datagroup.list(self.fields_keys, self.do_process_groups, self.do_process_dataset);
});
},
on_record_saved: function(r) {
var id = this.form_dialog.form.datarecord.id;
this.on_reload_record(id);
},
do_change_color: function(record_id, $e) {
do_process_groups: function(groups) {
this.do_clear_groups();
this.dataset.ids = [];
var self = this,
id = record_id,
colors = '#FFFFFF,#CCCCCC,#FFC7C7,#FFF1C7,#E3FFC7,#C7FFD5,#C7FFFF,#C7D5FF,#E3C7FF,#FFC7F1'.split(','),
$cpicker = $(QWeb.render('KanbanColorPicker', { colors : colors, columns: 2 }));
$e.after($cpicker);
$cpicker.mouseenter(function() {
clearTimeout($cpicker.data('timeoutId'));
}).mouseleave(function(evt) {
var timeoutId = setTimeout(function() { $cpicker.remove() }, 500);
$cpicker.data('timeoutId', timeoutId);
});
$cpicker.find('a').click(function(evt) {
var data = {};
data[$e.data('name')] = $(this).data('color');
self.dataset.write(id, data, {}, function() {
self.on_reload_record(id);
});
$cpicker.remove();
return false;
});
},
/**
Reload one record in view.
record_id : reload record id.
*/
on_reload_record: function (record_id){
var self = this;
this.dataset.read_ids([record_id], _.keys(self.fields_view.fields), function (records) {
if (records.length > 0) {
for (var i=0, ii=self.all_display_data.length; i < ii; i++) {
for(j=0, jj=self.all_display_data[i].records.length; j < jj; j++) {
if (self.all_display_data[i].records[j].id == record_id) {
_.extend(self.all_display_data[i].records[j], records[0]);
self.$element.find("#main_" + record_id).children().remove();
self.$element.find("#main_" + record_id).append(
self.qweb.render('kanban-box', self.get_qweb_context(self.all_display_data[i].records[j]))
);
break;
}
}
}
self.$element.find("#main_" + record_id + " .oe_kanban_action").click(self.on_action_clicked);
self.$element.find("#main_" + record_id + " .oe_kanban_box_show_onclick_trigger").click(function() {
$(this).parent("#main_" + record_id + " .oe_kanban_box").find(".oe_kanban_box_show_onclick").toggle();
});
}
});
},
do_delete: function (id) {
var self = this;
return $.when(this.dataset.unlink([id])).then(function () {
self.drop_records(id);
});
},
drop_records: function (id) {
var self = this;
_.each(self.all_display_data, function(data, index) {
_.each(data.records, function(record, index_row) {
if (parseInt(record.id) == id) {
self.all_display_data[index]['records'].splice(index_row, 1);
self.all_display_data[index]['ids'].splice(index_row, 1);
return false;
}
});
});
self.$element.find("#main_" + id).remove();
},
on_execute_button_click: function (dataset, button_attrs, record_id) {
var self = this;
this.do_execute_action(
button_attrs, dataset,
record_id, function () {
self.on_reload_record(record_id);
}
);
},
on_receive_record: function (event, ui) {
var self = this;
var from = ui.item.index();
var search_action = false;
var to = ui.item.prev().index() || 0;
if (!ui.item.attr("id")) {
return false;
}
if (self.fields_view.fields.sequence != undefined && ((self.source_index.index >= 0 && self.source_index.index != from) ||
(self.source_index.column && self.source_index.column != ui.item.parent().attr('id')))) {
var child_record = ui.item.parent().children();
var data, sequence = 1, index = to;
child_record.splice(0, to);
var flag = false;
if (to >= 0 && child_record) {
var record_id = parseInt($(child_record).attr("id").split("_")[1]);
if (record_id) {
_.each(self.all_display_data, function(data, index) {
_.each(data.records, function(record, index_row) {
if(record_id == record.id && record.sequence) {
sequence = record.sequence;
flag = true;
return false;
}
});
if(flag) {return false;}
});
}
}
_.each(child_record, function (child) {
var child_id = parseInt($(child).attr("id").split("_")[1]);
if (child_id) {
flag = false;
_.each(self.all_display_data, function(data, index) {
_.each(data.records, function(record, index_row) {
if(parseInt(record.id) == child_id) {
self.all_display_data[index]['records'][index_row]['sequence'] = sequence;
flag = true;
return false;
}
});
if (flag) {return false;}
});
self.dataset.write(child_id, {sequence: sequence});
sequence++;
search_action = true;
}
});
}
if (self.group_by.length > 0 && self.source_index.column && self.source_index.column != ui.item.parent().attr('id')) {
var value = ui.item.closest("td").attr("id");
if (value) {
var data_val = {};
var wirte_id = parseInt(ui.item.attr("id").split("_")[1]);
value = value.split("_")[1];
if (value == 'false') {
value = false;
}
var update_record = false;
_.each(self.all_display_data, function(data, index) {
_.each(data.records, function(record, index_row) {
if(parseInt(record.id) == wirte_id) {
self.all_display_data[index]['records'][index_row][self.group_by[0]] = value;
update_record = self.all_display_data[index]['records'].splice(index_row,1)
return false;
}
});
if (update_record) {return false;}
});
_.each(self.all_display_data, function(data, index) {
if (data.value == value || (data.value == 'false' && value == false)) {
self.all_display_data[index]['records'].push(update_record[0]);
}
});
data_val[self.group_by[0]] = value;
self.dataset.write(wirte_id, data_val);
search_action = true;
}
}
if (search_action) {
self.on_reload_kanban();
}
this.source_index = {};
},
on_reload_kanban: function() {
var self = this;
_.each(self.all_display_data, function(data, index) {
if (data.records.length > 0){
_.each(data.records, function(record) {
self.$element.find("#main_" + record.id).children().remove();
self.$element.find("#main_" + record.id).append(
self.qweb.render('kanban-box', self.get_qweb_context(record))
);
});
}
});
this.$element.find('.oe_kanban_action').click(this.on_action_clicked);
this.$element.find('.oe_kanban_box_show_onclick_trigger').click(function() {
$(this).parent('.oe_kanban_box').find('.oe_kanban_box_show_onclick').toggle();
});
},
on_action_clicked: function(evt) {
evt.preventDefault();
var $action = $(evt.currentTarget),
record_id = parseInt($action.closest(".oe_kanban_record").attr("id").split('_')[1]),
type = $action.data('type');
if (type == 'delete') {
this.do_delete(record_id);
} else if (type == 'edit') {
this.do_edit_record(record_id);
} else if (type == 'color') {
this.do_change_color(record_id, $action);
} else {
var button_attrs = $action.data();
this.on_button_click(button_attrs, record_id);
}
},
do_transform_record: function(record) {
var self = this,
new_record = {};
_.each(record, function(value, name) {
var r = _.clone(self.fields_view.fields[name]);
r.raw_value = value;
r.value = openerp.web.format_value(value, r);
new_record[name] = r;
});
return new_record;
},
do_search: function (domain, context, group_by) {
var self = this;
self.group_by = group_by;
var self = this,
group_by = self.group_by;
if (!group_by.length && this.fields_view.arch.attrs.default_group_by) {
group_by = [this.fields_view.arch.attrs.default_group_by];
self.group_by = group_by;
}
self.datagroup = new openerp.web.DataGroup(self, self.model, domain, context, group_by);
self.datagroup.list(
_.keys(self.fields_view.fields),
function (groups) {
self.dataset.ids = [];
self.groups = groups;
if (groups.length) {
self.do_render_group(groups);
} else {
self.all_display_data = [];
self.on_show_data();
}
},
function (dataset) {
self.groups = [];
self.dataset.read_slice(_.keys(self.fields_view.fields), {}, function(records) {
if (records.length) {
self.all_display_data = [{'records': records, 'value':false, 'header' : false, 'ids': self.dataset.ids}];
} else {
self.all_display_data = [];
}
self.$element.find(".oe_kanban_view").remove();
self.on_show_data();
});
}
);
},
do_render_group : function (datagroups) {
this.all_display_data = [];
var self = this,
remaining = datagroups.length - 1;
_.each(datagroups, function (group, index) {
var group_name = group.value;
var group_value = group.value;
if (!group.value) {
group_name = "Undefined";
group_value = 'false';
} else if (group.value instanceof Array) {
remaining = groups.length - 1,
groups_array = [];
_.each(groups, function (group, index) {
var group_name = group.value,
group_value = group.value,
group_aggregates = {};
if (group.value instanceof Array) {
group_name = group.value[1];
group_value = group.value[0];
}
var group_aggregates = {};
_.each(self.aggregates, function(value, key) {
group_aggregates[value] = group.aggregates[key];
});
var dataset = new openerp.web.DataSetSearch(self, self.dataset.model, group.context, group.domain);
self.$element.find(".oe_kanban_view").remove();
dataset.read_slice(_.keys(self.fields_view.fields), {'domain': group.domain, 'context': group.context}, function(records) {
dataset.read_slice(self.fields_keys, {'domain': group.domain, 'context': group.context}, function(records) {
self.dataset.ids.push.apply(self.dataset.ids, dataset.ids);
self.all_display_data[index] = {"value" : group_value, "records" : records, 'header' : group_name, 'ids' : dataset.ids, 'aggregates' : group_aggregates};
groups_array[index] = new openerp.web_kanban.KanbanGroup(self, records, group_value, group_name, group_aggregates);
if (!remaining--) {
self.dataset.index = self.dataset.ids.length ? 0 : null;
self.on_show_data();
self.do_add_groups(groups_array);
}
});
});
},
do_process_dataset: function(dataset) {
var self = this;
this.do_clear_groups();
this.dataset.read_slice(this.fields_keys, {}, function(records) {
var groups = [];
while (records.length) {
for (var i = 0; i < self.default_nr_columns; i++) {
if (!groups[i]) {
groups[i] = [];
}
groups[i].push(records.shift());
}
}
for (var i = 0; i < groups.length; i++) {
groups[i] = new openerp.web_kanban.KanbanGroup(self, _.compact(groups[i]));
}
self.do_add_groups(groups);
});
},
do_reload: function() {
this.do_search(this.search_domain, this.search_context, this.search_group_by);
},
do_clear_groups: function() {
_.each(this.groups, function(group) {
group.stop();
});
this.groups = [];
this.$element.find('.oe_kanban_groups_headers, .oe_kanban_groups_records').empty();
},
do_add_groups: function(groups) {
var self = this;
_.each(groups, function(group) {
self.groups[group.undefined_title ? 'unshift' : 'push'](group);
});
_.each(this.groups, function(group) {
group.appendTo(self.$element.find('.oe_kanban_groups_headers'));
});
this.on_groups_started();
},
on_groups_started: function() {
var self = this;
this.compute_groups_width();
if (this.group_by) {
this.$element.find('.oe_kanban_column').sortable({
connectWith: '.oe_kanban_column',
handle : '.oe_kanban_draghandle',
start: function(event, ui) {
self.currently_dragging.index = ui.item.index();
self.currently_dragging.group = ui.item.parents('.oe_kanban_column:first').data('widget');
},
stop: function(event, ui) {
var record = ui.item.data('widget'),
old_index = self.currently_dragging.index,
new_index = ui.item.index(),
old_group = self.currently_dragging.group,
new_group = ui.item.parents('.oe_kanban_column:first').data('widget');
if (!(old_group.title === new_group.title && old_group.value === new_group.value && old_index == new_index)) {
self.on_record_moved(record, old_group, old_index, new_group, new_index);
}
},
scroll: false
});
} else {
this.$element.find('.oe_kanban_draghandle').removeClass('oe_kanban_draghandle');
}
},
on_record_moved : function(record, old_group, old_index, new_group, new_index) {
if (old_group === new_group) {
new_group.records.splice(old_index, 1);
new_group.records.splice(new_index, 0, record);
new_group.do_save_sequences();
} else {
old_group.records.splice(old_index, 1);
new_group.records.splice(new_index, 0, record);
record.group = new_group;
var data = {};
data[this.group_by] = new_group.value;
this.dataset.write(record.id, data, {}, function() {
record.do_reload();
new_group.do_save_sequences();
});
}
},
do_show: function () {
this.$element.show();
},
do_hide: function () {
this.$element.hide();
},
compute_groups_width: function() {
var unfolded = 0;
_.each(this.groups, function(group) {
unfolded += group.state.folded ? 0 : 1;
group.$element.css('width', '');
});
_.each(this.groups, function(group) {
if (!group.state.folded) {
group.$element.css('width', Math.round(100/unfolded) + '%');
}
});
}
});
openerp.web_kanban.KanbanGroup = openerp.web.Widget.extend({
template: 'KanbanView.group_header',
init: function (parent, records, value, title, aggregates) {
var self = this;
this._super(parent);
this.view = parent;
this.value = value;
this.title = title;
if (title === false) {
this.title = _t('Undefined');
this.undefined_title = true;
}
this.aggregates = aggregates || {};
var key = this.view.group_by + '-' + value;
if (!this.view.state.groups[key]) {
this.view.state.groups[key] = {
folded: false
}
}
this.state = this.view.state.groups[key];
this.$records = null;
this.records = _.map(records, function(record) {
return new openerp.web_kanban.KanbanRecord(self, record);
});
},
start: function() {
var self = this,
def = this._super();
this.$records = $(QWeb.render('KanbanView.group_records_container', { widget : this}));
this.$records.appendTo(this.view.$element.find('.oe_kanban_groups_records'));
_.each(this.records, function(record) {
record.appendTo(self.$records);
});
this.$element.find(".oe_kanban_fold_icon").click(function() {
self.do_toggle_fold();
self.view.compute_groups_width();
return false;
});
if (this.state.folded) {
this.do_toggle_fold();
}
this.$element.data('widget', this);
this.$records.data('widget', this);
return def;
},
stop: function() {
this._super();
if (this.$records) {
this.$records.remove();
}
},
remove_record: function(id, remove_from_dataset) {
for (var i = 0, ii = this.records.length; i < ii; i++) {
if (this.records[i]['id'] === id) {
this.records.splice(i, 1);
}
}
},
do_toggle_fold: function(compute_width) {
this.$element.toggleClass('oe_kanban_group_folded');
this.$records.find('.oe_kanban_record').toggle();
this.state.folded = this.$element.is('.oe_kanban_group_folded');
},
do_save_sequences: function() {
var self = this;
if (_.indexOf(this.view.fields_keys, 'sequence') > -1) {
_.each(this.records, function(record, index) {
self.view.dataset.write(record.id, { sequence : index });
});
}
}
});
openerp.web_kanban.KanbanRecord = openerp.web.Widget.extend({
template: 'KanbanView.record',
init: function (parent, record) {
this._super(parent);
this.group = parent;
this.view = parent.view;
this.id = null;
this.set_record(record);
if (!this.view.state.records[this.id]) {
this.view.state.records[this.id] = {
folded: false
};
}
this.state = this.view.state.records[this.id];
},
set_record: function(record) {
this.id = record.id;
this.record = this.transform_record(record);
},
start: function() {
this._super();
this.$element.data('widget', this);
this.bind_events();
},
transform_record: function(record) {
var self = this,
new_record = {};
_.each(record, function(value, name) {
var r = _.clone(self.view.fields_view.fields[name]);
r.raw_value = value;
r.value = openerp.web.format_value(value, r);
new_record[name] = r;
});
return new_record;
},
render: function() {
var ctx = {
record: this.record,
widget: this
}
for (var p in this) {
if (_.startsWith(p, 'kanban_')) {
ctx[p] = _.bind(this[p], this);
}
}
return this._super({
'content': this.view.qweb.render('kanban-box', ctx)
});
},
bind_events: function() {
var self = this,
$show_on_click = self.$element.find('.oe_kanban_box_show_onclick');
$show_on_click.toggle(this.state.folded);
this.$element.find('.oe_kanban_box_show_onclick_trigger').click(function() {
$show_on_click.toggle();
self.state.folded = !self.state.folded;
});
this.$element.find('.oe_kanban_action').click(function() {
var $action = $(this),
type = $action.data('type') || 'button',
method = 'do_action_' + type;
if (typeof self[method] === 'function') {
self[method]($action);
} else {
self.do_warn("Kanban: no action for type : " + type);
}
return false;
});
},
do_action_delete: function($action) {
var self = this;
if (confirm(_t("Are you sure you want to delete this record ?"))) {
return $.when(this.view.dataset.unlink([this.id])).then(function() {
self.group.remove_record(self.id)
self.stop();
});
}
},
do_action_edit: function($action) {
var self = this;
if ($action.attr('target') === 'dialog') {
this.view.form_dialog.select_id(this.id).then(function() {
self.view.form_dialog.open();
});
} else {
if (self.view.dataset.select_id(this.id)) {
this.view.do_switch_view('form');
} else {
this.do_warn("Kanban: could not find id#" + id);
}
}
},
do_action_color: function($action) {
var self = this,
colors = '#FFFFFF,#CCCCCC,#FFC7C7,#FFF1C7,#E3FFC7,#C7FFD5,#C7FFFF,#C7D5FF,#E3C7FF,#FFC7F1'.split(','),
$cpicker = $(QWeb.render('KanbanColorPicker', { colors : colors, columns: 2 }));
$action.after($cpicker);
$cpicker.mouseenter(function() {
clearTimeout($cpicker.data('timeoutId'));
}).mouseleave(function(evt) {
var timeoutId = setTimeout(function() { $cpicker.remove() }, 500);
$cpicker.data('timeoutId', timeoutId);
});
$cpicker.find('a').click(function() {
var data = {};
data[$action.data('name')] = $(this).data('color');
self.view.dataset.write(self.id, data, {}, function() {
self.record[$action.data('name')] = $(this).data('color');
self.do_reload();
});
$cpicker.remove();
return false;
});
},
do_action_object: function ($action) {
var button_attrs = $action.data();
this.view.do_execute_action(button_attrs, this.view.dataset, this.id, this.do_reload);
},
do_reload: function() {
var self = this;
this.view.dataset.read_ids([this.id], this.view.fields_keys, function(records) {
if (records.length) {
self.set_record(records[0]);
self.do_render();
} else {
self.stop();
}
});
},
do_render: function() {
this.$element.html(this.render());
this.bind_events();
},
kanban_color: function(variable) {
var number_of_color_schemes = 10,
index = 0;
switch (typeof(variable)) {
case 'string':
for (var i=0, ii=variable.length; i<ii; i++) {
index += variable.charCodeAt(i);
}
break;
case 'number':
index = Math.round(variable);
break;
default:
return '';
}
var color = (index % number_of_color_schemes);
return 'oe_kanban_color_' + color;
},
kanban_gravatar: function(email, size) {
size = size || 22;
var email_md5 = $.md5(email);
return 'http://www.gravatar.com/avatar/' + email_md5 + '.png?s=' + size;
},
kanban_image: function(model, field, id) {
id = id || '';
return '/web/binary/image?session_id=' + this.session.session_id + '&model=' + model + '&field=' + field + '&id=' + id;
},
kanban_text_ellipsis: function(s, size) {
size = size || 160;
if (!s) {
return '';
}
return s.substr(0, size) + '...';
}
});
};

View File

@ -1,33 +1,43 @@
<template>
<t t-name="KanbanView">
<table style="width:100%;" class="oe_kanban_view">
<tr>
<td>
<div class="oe_form_header">
<button type="button" class="oe_kanban_button_new">New</button>
</div>
</td>
</tr>
<tr>
<td t-foreach="data" t-as="columns" class="oe_table_column" t-att-id="'column_' + columns.value">
<img t-att-id="columns.value" class="fold-columns-icon" src="/web_kanban/static/src/img/minus-icon.png"/>
<div class="oe_fold_column" t-att-id="'column_' + columns.value">
<div class="oe_column_heading" t-if="columns.value and columns.header">
<t t-esc="columns.header"/>
</div>
<div t-foreach="columns.aggregates or {}" t-as="aggregate">
<i><u><t t-esc="aggregate"/>:</u> <t t-esc="aggregate_value"/></i>
<div class="oe_kanban_header">
<button type="button" class="oe_kanban_button_new">New</button>
</div>
<div class="oe_kanban_view">
<table style="width:100%;" class="oe_kanban_groups">
<tr class="oe_kanban_groups_headers">
</tr>
<tr class="oe_kanban_groups_records">
</tr>
</table>
</div>
</t>
<t t-name="KanbanView.group_header">
<td class="oe_kanban_group_header">
<t t-if="widget.view.group_by">
<div class="oe_kanban_fold_icon"></div>
<div class="oe_fold_column">
<div t-attf-class="oe_kanban_group_title #{widget.undefined_title ? 'oe_kanban_group_title_undefined' : ''}">
<t t-esc="widget.title"/>
</div>
<ul class="oe_kanban_aggregates">
<li t-foreach="widget.aggregates" t-as="aggregate">
<span><t t-esc="aggregate"/>:</span> <t t-esc="aggregate_value"/>
</li>
</ul>
</div>
</td>
</tr>
<tr>
<td t-foreach="data" t-as="columns" class="oe_column oe_table_column" t-att-id="'column_' + columns.value" t-attf-style="width: #{Math.round(99 / data.length)}%">
<p t-if="columns.header" class="oe_vertical_text" t-att-id="'column_' + columns.value"><t t-esc="columns.header"/></p>
<div t-foreach="columns.records" t-as="record" class="oe_fold_column oe_kanban_record" t-att-id="'main_' + record.id"/>
</td>
</tr>
</table>
<p t-if="widget.title" class="oe_kanban_group_title_vertical"><t t-esc="widget.title"/></p>
</t>
</td>
</t>
<t t-name="KanbanView.group_records_container">
<td class="oe_kanban_column">
</td>
</t>
<t t-name="KanbanView.record">
<div class="oe_fold_column oe_kanban_record">
<t t-raw="content"/>
</div>
</t>
<t t-name="KanbanColorPicker">
<table cellspacing="0" cellpadding="0" border="0" class="oe_kanban_color_picker">