[REF] web: kanban: adapt code to new style
This commit adapts some kanban files to the new style and guidelines.
This commit is contained in:
@@ -4,36 +4,33 @@ odoo.define('web.KanbanColumn', function (require) {
|
||||
var config = require('web.config');
|
||||
var core = require('web.core');
|
||||
var Dialog = require('web.Dialog');
|
||||
var view_dialogs = require('web.view_dialogs');
|
||||
var quick_create = require('web.kanban_quick_create');
|
||||
var kanban_quick_create = require('web.kanban_quick_create');
|
||||
var KanbanRecord = require('web.KanbanRecord');
|
||||
var view_dialogs = require('web.view_dialogs');
|
||||
var Widget = require('web.Widget');
|
||||
|
||||
var _t = core._t;
|
||||
var QWeb = core.qweb;
|
||||
var RecordQuickCreate = quick_create.RecordQuickCreate;
|
||||
var RecordQuickCreate = kanban_quick_create.RecordQuickCreate;
|
||||
|
||||
var KanbanColumn = Widget.extend({
|
||||
template: "KanbanView.Group",
|
||||
events: {
|
||||
'click .o_column_edit': 'edit_column',
|
||||
'click .o_column_delete': 'delete_column',
|
||||
'click .o_column_archive': 'archive_records',
|
||||
'click .o_column_unarchive': 'unarchive_records',
|
||||
'click .o_kanban_quick_add': 'add_quick_create',
|
||||
'click .o_kanban_load_more': 'load_more',
|
||||
'click .o_kanban_toggle_fold': 'toggle_fold',
|
||||
},
|
||||
template: 'KanbanView.Group',
|
||||
custom_events: {
|
||||
'kanban_record_delete': 'delete_record',
|
||||
'cancel_quick_create': 'cancel_quick_create',
|
||||
'quick_create_add_record': 'quick_create_add_record',
|
||||
cancel_quick_create: '_onCancelQuickCreate',
|
||||
kanban_record_delete: '_onDeleteRecord',
|
||||
quick_create_add_record: '_onQuickCreateAddRecord',
|
||||
},
|
||||
events: {
|
||||
'click .o_column_edit': '_onEditColumn',
|
||||
'click .o_column_delete': '_onDeleteColumn',
|
||||
'click .o_column_archive': '_onArchiveRecords',
|
||||
'click .o_column_unarchive': '_onUnarchiveRecords',
|
||||
'click .o_kanban_quick_add': '_onAddQuickCreate',
|
||||
'click .o_kanban_load_more': '_onLoadMore',
|
||||
'click .o_kanban_toggle_fold': '_onToggleFold',
|
||||
},
|
||||
/**
|
||||
* @param {any} parent
|
||||
* @param {any} data
|
||||
* @param {any} options
|
||||
* @param {any} recordOptions
|
||||
* @override
|
||||
*/
|
||||
init: function (parent, data, options, recordOptions) {
|
||||
this._super(parent);
|
||||
@@ -81,14 +78,14 @@ var KanbanColumn = Widget.extend({
|
||||
}
|
||||
},
|
||||
/**
|
||||
* @returns {Deferred}
|
||||
* @override
|
||||
*/
|
||||
start: function () {
|
||||
var self = this;
|
||||
this.$header = this.$('.o_kanban_header');
|
||||
|
||||
for (var i = 0; i < this.data_records.length; i++) {
|
||||
this.add_record(this.data_records[i], {no_update: true});
|
||||
this.addRecord(this.data_records[i], {no_update: true});
|
||||
}
|
||||
this.$header.tooltip();
|
||||
|
||||
@@ -105,7 +102,7 @@ var KanbanColumn = Widget.extend({
|
||||
cursor: 'move',
|
||||
over: function () {
|
||||
self.$el.addClass('o_kanban_hover');
|
||||
self.update_column();
|
||||
self._update();
|
||||
},
|
||||
out: function () {
|
||||
self.$el.removeClass('o_kanban_hover');
|
||||
@@ -118,34 +115,61 @@ var KanbanColumn = Widget.extend({
|
||||
if (index >= 0) {
|
||||
if ($.contains(self.$el[0], record.$el[0])) {
|
||||
// resequencing records
|
||||
self.trigger_up('kanban_column_resequence', {ids: self.get_ids()});
|
||||
self.trigger_up('kanban_column_resequence', {ids: self._getIDs()});
|
||||
}
|
||||
} else {
|
||||
// adding record to this column
|
||||
self.trigger_up('kanban_column_add_record', {record: record, ids: self.get_ids()});
|
||||
self.trigger_up('kanban_column_add_record', {record: record, ids: self._getIDs()});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
this.$el.click(function (event) {
|
||||
if (self.folded) {
|
||||
self.toggle_fold(event);
|
||||
self._onToggleFold(event);
|
||||
}
|
||||
});
|
||||
this.update_column();
|
||||
this._update();
|
||||
|
||||
return this._super.apply(this, arguments);
|
||||
},
|
||||
|
||||
is_empty: function () {
|
||||
return !this.records.length;
|
||||
},
|
||||
//--------------------------------------------------------------------------
|
||||
// Public
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
add_record: function (data, options) {
|
||||
var record = new KanbanRecord(this, data, this.record_options);
|
||||
/**
|
||||
* Adds the quick create record to the top of the column.
|
||||
*/
|
||||
addQuickCreate: function () {
|
||||
if (this.quickCreateWidget) {
|
||||
return;
|
||||
}
|
||||
var self = this;
|
||||
var width = this.records.length ? this.records[0].$el.innerWidth() : this.$el.width() - 8;
|
||||
this.quickCreateWidget = new RecordQuickCreate(this, width);
|
||||
this.quickCreateWidget.insertAfter(this.$header);
|
||||
this.quickCreateWidget.$el.focusout(function () {
|
||||
var hasFocus = (self.quickCreateWidget.$(':focus').length > 0);
|
||||
if (! hasFocus && self.quickCreateWidget) {
|
||||
self._cancelQuickCreate();
|
||||
}
|
||||
});
|
||||
},
|
||||
/**
|
||||
* Adds a record in the column.
|
||||
*
|
||||
* @param {Object} recordState
|
||||
* @param {Object} options
|
||||
* @params {string} options.position 'before' to add the record at the top,
|
||||
* added at the bottom by default
|
||||
* @params {Boolean} options.no_update set to true not to update the column
|
||||
*/
|
||||
addRecord: function (recordState, options) {
|
||||
var record = new KanbanRecord(this, recordState, this.record_options);
|
||||
this.records.push(record);
|
||||
if (options.position === 'before') {
|
||||
record.insertAfter(this.quick_create_widget ? this.quick_create_widget.$el : this.$header);
|
||||
record.insertAfter(this.quickCreateWidget ? this.quickCreateWidget.$el : this.$header);
|
||||
} else {
|
||||
var $load_more = this.$('.o_kanban_load_more');
|
||||
if ($load_more.length) {
|
||||
@@ -155,19 +179,43 @@ var KanbanColumn = Widget.extend({
|
||||
}
|
||||
}
|
||||
if (!options.no_update) {
|
||||
this.update_column();
|
||||
this._update();
|
||||
}
|
||||
},
|
||||
/**
|
||||
* @returns {Boolean} true iff the column is empty
|
||||
*/
|
||||
isEmpty: function () {
|
||||
return !this.records.length;
|
||||
},
|
||||
|
||||
get_ids: function () {
|
||||
//--------------------------------------------------------------------------
|
||||
// Private
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Destroys the QuickCreate widget.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
_cancelQuickCreate: function () {
|
||||
this.quickCreateWidget.destroy();
|
||||
this.quickCreateWidget = undefined;
|
||||
},
|
||||
/**
|
||||
* @returns {integer[]} the res_ids of the records in the column
|
||||
*/
|
||||
_getIDs: function () {
|
||||
var ids = [];
|
||||
this.$('.o_kanban_record').each(function (index, r) {
|
||||
ids.push($(r).data('record').id);
|
||||
});
|
||||
return ids;
|
||||
},
|
||||
|
||||
update_column: function () {
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_update: function () {
|
||||
var title = this.folded ? this.title + ' (' + this.size + ')' : this.title;
|
||||
this.$header.find('.o_column_title').text(title);
|
||||
this.$header.find('.o-kanban-count').text(this.records.length);
|
||||
@@ -183,29 +231,42 @@ var KanbanColumn = Widget.extend({
|
||||
}
|
||||
},
|
||||
|
||||
archive_records: function (event) {
|
||||
//--------------------------------------------------------------------------
|
||||
// Handlers
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_onAddQuickCreate: function () {
|
||||
this.addQuickCreate();
|
||||
},
|
||||
/**
|
||||
* @private
|
||||
* @param {MouseEvent} event
|
||||
*/
|
||||
_onArchiveRecords: function (event) {
|
||||
event.preventDefault();
|
||||
this.trigger_up('kanban_column_archive_records', {archive: true});
|
||||
},
|
||||
|
||||
unarchive_records: function (event) {
|
||||
event.preventDefault();
|
||||
this.trigger_up('kanban_column_archive_records', {archive: false});
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_onCancelQuickCreate: function () {
|
||||
this.cancelQuickCreate();
|
||||
},
|
||||
|
||||
toggle_fold: function (event) {
|
||||
event.preventDefault();
|
||||
this.trigger_up('column_toggle_fold');
|
||||
},
|
||||
|
||||
delete_column: function (event) {
|
||||
/**
|
||||
* @private
|
||||
* @param {MouseEvent} event
|
||||
*/
|
||||
_onDeleteColumn: function (event) {
|
||||
event.preventDefault();
|
||||
var buttons = [
|
||||
{
|
||||
text: _t("Ok"),
|
||||
classes: 'btn-primary',
|
||||
close: true,
|
||||
click: this.trigger_up.bind(this, 'kanban_column_delete')
|
||||
click: this.trigger_up.bind(this, 'kanban_column_delete'),
|
||||
},
|
||||
{text: _t("Cancel"), close: true}
|
||||
];
|
||||
@@ -217,8 +278,24 @@ var KanbanColumn = Widget.extend({
|
||||
}),
|
||||
}).open();
|
||||
},
|
||||
|
||||
edit_column: function (event) {
|
||||
/**
|
||||
* @private
|
||||
* @param {OdooEvent} event
|
||||
*/
|
||||
_onDeleteRecord: function (event) {
|
||||
var self = this;
|
||||
event.data.parent_id = this.db_id;
|
||||
event.data.after = function cleanup() {
|
||||
var index = self.records.indexOf(event.data.record);
|
||||
self.records.splice(index, 1);
|
||||
self._update();
|
||||
};
|
||||
},
|
||||
/**
|
||||
* @private
|
||||
* @param {MouseEvent} event
|
||||
*/
|
||||
_onEditColumn: function (event) {
|
||||
event.preventDefault();
|
||||
new view_dialogs.FormViewDialog(this, {
|
||||
res_model: this.relation,
|
||||
@@ -227,47 +304,37 @@ var KanbanColumn = Widget.extend({
|
||||
on_saved: this.trigger_up.bind(this, 'reload'),
|
||||
}).open();
|
||||
},
|
||||
|
||||
delete_record: function (event) {
|
||||
var self = this;
|
||||
event.data.parent_id = this.db_id;
|
||||
event.data.after = function cleanup() {
|
||||
var index = self.records.indexOf(event.data.record);
|
||||
self.records.splice(index, 1);
|
||||
self.update_column();
|
||||
};
|
||||
},
|
||||
|
||||
add_quick_create: function () {
|
||||
if (this.quick_create_widget) {
|
||||
return;
|
||||
}
|
||||
var self = this;
|
||||
var width = this.records.length ? this.records[0].$el.innerWidth() : this.$el.width() - 8;
|
||||
this.quick_create_widget = new RecordQuickCreate(this, width);
|
||||
this.quick_create_widget.insertAfter(this.$header);
|
||||
this.quick_create_widget.$el.focusout(function () {
|
||||
var hasFocus = (self.quick_create_widget.$(':focus').length > 0);
|
||||
if (! hasFocus && self.quick_create_widget) {
|
||||
self.cancel_quick_create();
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
cancel_quick_create: function () {
|
||||
this.quick_create_widget.destroy();
|
||||
this.quick_create_widget = undefined;
|
||||
},
|
||||
|
||||
quick_create_add_record: function (event) {
|
||||
this.trigger_up('quick_create_record', event.data);
|
||||
},
|
||||
|
||||
load_more: function (event) {
|
||||
/**
|
||||
* @private
|
||||
* @param {MouseEvent} event
|
||||
*/
|
||||
_onLoadMore: function (event) {
|
||||
event.preventDefault();
|
||||
this.trigger_up('kanban_load_more');
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @param {OdooEvent} event
|
||||
*/
|
||||
_onQuickCreateAddRecord: function (event) {
|
||||
this.trigger_up('quick_create_record', event.data);
|
||||
},
|
||||
/**
|
||||
* @private
|
||||
* @param {MouseEvent} event
|
||||
*/
|
||||
_onToggleFold: function (event) {
|
||||
event.preventDefault();
|
||||
this.trigger_up('column_toggle_fold');
|
||||
},
|
||||
/**
|
||||
* @private
|
||||
* @param {MouseEvent} event
|
||||
*/
|
||||
_onUnarchiveRecords: function (event) {
|
||||
event.preventDefault();
|
||||
this.trigger_up('kanban_column_archive_records', {archive: false});
|
||||
},
|
||||
});
|
||||
|
||||
return KanbanColumn;
|
||||
|
||||
@@ -59,7 +59,7 @@ var KanbanController = BasicController.extend({
|
||||
var data = self.model.get(self.handle, {raw: true});
|
||||
if (data.groupedBy.length > 0 && data.count > 0 && self.on_create === 'quick_create') {
|
||||
// Activate the quick create in the first column
|
||||
self.renderer.add_quick_create();
|
||||
self.renderer.addQuickCreate();
|
||||
} else if (self.on_create && self.on_create !== 'quick_create') {
|
||||
// Execute the given action
|
||||
self.do_action(self.on_create, {
|
||||
@@ -101,7 +101,7 @@ var KanbanController = BasicController.extend({
|
||||
* @param {string} id local id from the basic record data
|
||||
*/
|
||||
_confirmSave: function (id) {
|
||||
this.renderer.update_record(this.model.get(id));
|
||||
this.renderer.updateRecord(this.model.get(id));
|
||||
},
|
||||
/**
|
||||
* @todo this is dead code right now. resurrect this?
|
||||
@@ -181,7 +181,7 @@ var KanbanController = BasicController.extend({
|
||||
.then(function () {
|
||||
_.each(column_db_ids, function (db_id) {
|
||||
var data = self.model.get(db_id);
|
||||
self.renderer.update_column(db_id, data);
|
||||
self.renderer.updateColumn(db_id, data);
|
||||
});
|
||||
});
|
||||
}).fail(this.reload.bind(this));
|
||||
@@ -207,7 +207,7 @@ var KanbanController = BasicController.extend({
|
||||
.toggleActive(record_ids, active_value, column.db_id)
|
||||
.then(function (db_id) {
|
||||
var data = self.model.get(db_id);
|
||||
self.renderer.update_column(db_id, data);
|
||||
self.renderer.updateColumn(db_id, data);
|
||||
});
|
||||
}
|
||||
},
|
||||
@@ -228,8 +228,8 @@ var KanbanController = BasicController.extend({
|
||||
this.model
|
||||
.deleteRecords([column.db_id], relatedModelName, this.handle)
|
||||
.done(function () {
|
||||
if (column.is_empty()) {
|
||||
self.renderer.remove_widget(column);
|
||||
if (column.isEmpty()) {
|
||||
self.renderer.removeWidget(column);
|
||||
self._updateButtons();
|
||||
} else {
|
||||
self.reload();
|
||||
@@ -255,7 +255,7 @@ var KanbanController = BasicController.extend({
|
||||
var column = event.target;
|
||||
this.model.load_more(column.db_id).then(function (db_id) {
|
||||
var data = self.model.get(db_id);
|
||||
self.renderer.update_column(db_id, data);
|
||||
self.renderer.updateColumn(db_id, data);
|
||||
});
|
||||
},
|
||||
/**
|
||||
@@ -297,7 +297,7 @@ var KanbanController = BasicController.extend({
|
||||
return self.model
|
||||
.addRecordToGroup(data.id, records[0])
|
||||
.then(function (db_id) {
|
||||
column.add_record(self.model.get(db_id), {position: 'before'});
|
||||
column.addRecord(self.model.get(db_id), {position: 'before'});
|
||||
});
|
||||
}
|
||||
data.context['default_' + data.groupedBy[0]] = column.id;
|
||||
@@ -347,7 +347,7 @@ var KanbanController = BasicController.extend({
|
||||
var column = event.target;
|
||||
this.model.toggleGroup(column.db_id).then(function (db_id) {
|
||||
var data = self.model.get(db_id);
|
||||
self.renderer.update_column(db_id, data);
|
||||
self.renderer.updateColumn(db_id, data);
|
||||
});
|
||||
},
|
||||
/**
|
||||
|
||||
@@ -1,26 +1,30 @@
|
||||
odoo.define('web.KanbanModel', function (require) {
|
||||
"use strict";
|
||||
|
||||
/**
|
||||
* The KanbanModel extends the BasicModel to add Kanban specific features like
|
||||
* moving a record from a group to another, resequencing records...
|
||||
*/
|
||||
|
||||
var BasicModel = require('web.BasicModel');
|
||||
|
||||
return BasicModel.extend({
|
||||
load: function (params) {
|
||||
this.defaultGroupedBy = params.groupBy;
|
||||
params.groupedBy = params.groupedBy.length ? params.groupedBy : this.defaultGroupedBy;
|
||||
return this._super(params);
|
||||
},
|
||||
reload: function (id, options) {
|
||||
// if the groupBy is given in the options and if it is an empty array,
|
||||
// fallback on the default groupBy
|
||||
if (options && options.groupBy && !options.groupBy.length) {
|
||||
options.groupBy = this.defaultGroupedBy;
|
||||
}
|
||||
return this._super(id, options);
|
||||
},
|
||||
addRecordToGroup: function (group_id, res_id) {
|
||||
var group = this.localData[group_id];
|
||||
var KanbanModel = BasicModel.extend({
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Public
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Adds a record to a group in the localData, and fetch the record.
|
||||
*
|
||||
* @param {string} groupID localID of the group
|
||||
* @param {integer} resId id of the record
|
||||
* @returns {Deferred<string>} resolves to the local id of the new record
|
||||
*/
|
||||
addRecordToGroup: function (groupID, resId) {
|
||||
var group = this.localData[groupID];
|
||||
var new_record = this._makeDataPoint({
|
||||
res_id: res_id,
|
||||
res_id: resId,
|
||||
modelName: group.model,
|
||||
fields: group.fields,
|
||||
fieldNames: group.fieldNames,
|
||||
@@ -34,60 +38,13 @@ return BasicModel.extend({
|
||||
return result.id;
|
||||
});
|
||||
},
|
||||
moveRecord: function (record_id, group_id, parent_id) {
|
||||
var self = this;
|
||||
var parent = this.localData[parent_id];
|
||||
var new_group = this.localData[group_id];
|
||||
var changes = {};
|
||||
var groupedFieldName = parent.groupedBy[0];
|
||||
var groupedField = parent.fields[groupedFieldName];
|
||||
if (groupedField.type === 'many2one') {
|
||||
changes[groupedFieldName] = {
|
||||
id: new_group.res_id,
|
||||
display_name: new_group.value,
|
||||
};
|
||||
} else {
|
||||
changes[groupedFieldName] = new_group.value;
|
||||
}
|
||||
return this.notifyChanges(record_id, changes).then(function () {
|
||||
return self.save(record_id);
|
||||
}).then(function (result) {
|
||||
// Remove record from its current group
|
||||
var old_group;
|
||||
for (var i = 0; i < parent.count; i++) {
|
||||
old_group = self.localData[parent.data[i]];
|
||||
var index = _.indexOf(old_group.data, record_id);
|
||||
if (index >= 0) {
|
||||
old_group.data.splice(index, 1);
|
||||
old_group.count--;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Add record to its new group
|
||||
new_group.data.push(result.id);
|
||||
new_group.count++;
|
||||
return [old_group.id, new_group.id];
|
||||
});
|
||||
},
|
||||
resequence: function (modelName, res_ids, parent_id) {
|
||||
if ((res_ids.length <= 1)) {
|
||||
return $.when(parent_id); // there is nothing to sort
|
||||
}
|
||||
var self = this;
|
||||
var data = self.localData[parent_id];
|
||||
var def;
|
||||
if (data.fields.sequence) {
|
||||
def = this._rpc('/web/dataset/resequence')
|
||||
.params({model: modelName, ids: res_ids})
|
||||
.exec();
|
||||
}
|
||||
return $.when(def).then(function () {
|
||||
data.data = _.sortBy(data.data, function (d) {
|
||||
return _.indexOf(res_ids, d.res_id);
|
||||
});
|
||||
return parent_id;
|
||||
});
|
||||
},
|
||||
/**
|
||||
* Creates a new group from a name (performs a name_create).
|
||||
*
|
||||
* @param {string} name
|
||||
* @param {string} parentID localID of the parent of the group
|
||||
* @returns {Deferred<string>} resolves to the local id of the new group
|
||||
*/
|
||||
createGroup: function (name, parentID) {
|
||||
var self = this;
|
||||
var parent = this.localData[parentID];
|
||||
@@ -121,6 +78,97 @@ return BasicModel.extend({
|
||||
return newGroup.id;
|
||||
});
|
||||
},
|
||||
/**
|
||||
* @override
|
||||
*/
|
||||
load: function (params) {
|
||||
this.defaultGroupedBy = params.groupBy;
|
||||
params.groupedBy = params.groupedBy.length ? params.groupedBy : this.defaultGroupedBy;
|
||||
return this._super(params);
|
||||
},
|
||||
/**
|
||||
* Moves a record from a group to another.
|
||||
*
|
||||
* @param {string} recordID localID of the record
|
||||
* @param {string} groupID localID of the new group of the record
|
||||
* @param {string} parentID localID of the parent
|
||||
* @returns {Deferred<string[]>} resolves to a pair [oldGroupID, newGroupID]
|
||||
*/
|
||||
moveRecord: function (recordID, groupID, parentID) {
|
||||
var self = this;
|
||||
var parent = this.localData[parentID];
|
||||
var new_group = this.localData[groupID];
|
||||
var changes = {};
|
||||
var groupedFieldName = parent.groupedBy[0];
|
||||
var groupedField = parent.fields[groupedFieldName];
|
||||
if (groupedField.type === 'many2one') {
|
||||
changes[groupedFieldName] = {
|
||||
id: new_group.res_id,
|
||||
display_name: new_group.value,
|
||||
};
|
||||
} else {
|
||||
changes[groupedFieldName] = new_group.value;
|
||||
}
|
||||
return this.notifyChanges(recordID, changes).then(function () {
|
||||
return self.save(recordID);
|
||||
}).then(function (result) {
|
||||
// Remove record from its current group
|
||||
var old_group;
|
||||
for (var i = 0; i < parent.count; i++) {
|
||||
old_group = self.localData[parent.data[i]];
|
||||
var index = _.indexOf(old_group.data, recordID);
|
||||
if (index >= 0) {
|
||||
old_group.data.splice(index, 1);
|
||||
old_group.count--;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Add record to its new group
|
||||
new_group.data.push(result.id);
|
||||
new_group.count++;
|
||||
return [old_group.id, new_group.id];
|
||||
});
|
||||
},
|
||||
/**
|
||||
* @override
|
||||
*/
|
||||
reload: function (id, options) {
|
||||
// if the groupBy is given in the options and if it is an empty array,
|
||||
// fallback on the default groupBy
|
||||
if (options && options.groupBy && !options.groupBy.length) {
|
||||
options.groupBy = this.defaultGroupedBy;
|
||||
}
|
||||
return this._super(id, options);
|
||||
},
|
||||
/**
|
||||
* Resequences records.
|
||||
*
|
||||
* @param {string} modelName
|
||||
* @param {Array[integer]} resIDs the new sequence of ids
|
||||
* @param {string]} parentID the localID of the parent
|
||||
* @returns {Deferred<string>} resolves to the local id of the parent
|
||||
*/
|
||||
resequence: function (modelName, resIDs, parentID) {
|
||||
if ((resIDs.length <= 1)) {
|
||||
return $.when(parentID); // there is nothing to sort
|
||||
}
|
||||
var self = this;
|
||||
var data = self.localData[parentID];
|
||||
var def;
|
||||
if (data.fields.sequence) {
|
||||
def = this._rpc('/web/dataset/resequence')
|
||||
.params({model: modelName, ids: resIDs})
|
||||
.exec();
|
||||
}
|
||||
return $.when(def).then(function () {
|
||||
data.data = _.sortBy(data.data, function (d) {
|
||||
return _.indexOf(resIDs, d.res_id);
|
||||
});
|
||||
return parentID;
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
return KanbanModel;
|
||||
|
||||
});
|
||||
|
||||
@@ -14,14 +14,12 @@ var _t = core._t;
|
||||
|
||||
var KanbanRecord = Widget.extend({
|
||||
template: 'KanbanView.record',
|
||||
|
||||
events: {
|
||||
'click .oe_kanban_action': 'on_kanban_action_clicked',
|
||||
'click .o_kanban_manage_toggle_button': 'toggle_manage_pane',
|
||||
},
|
||||
|
||||
custom_events: {
|
||||
'kanban_update_record': 'update_record',
|
||||
kanban_update_record: 'update_record',
|
||||
},
|
||||
|
||||
init: function (parent, state, options) {
|
||||
|
||||
@@ -15,7 +15,7 @@ var ColumnQuickCreate = quick_create.ColumnQuickCreate;
|
||||
|
||||
var qweb = core.qweb;
|
||||
|
||||
function find_in_node(node, predicate) {
|
||||
function findInNode(node, predicate) {
|
||||
if (predicate(node)) {
|
||||
return node;
|
||||
}
|
||||
@@ -23,25 +23,25 @@ function find_in_node(node, predicate) {
|
||||
return undefined;
|
||||
}
|
||||
for (var i = 0; i < node.children.length; i++) {
|
||||
if (find_in_node(node.children[i], predicate)) {
|
||||
if (findInNode(node.children[i], predicate)) {
|
||||
return node.children[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function qweb_add_if(node, condition) {
|
||||
function qwebAddIf(node, condition) {
|
||||
if (node.attrs[qweb.prefix + '-if']) {
|
||||
condition = _.str.sprintf("(%s) and (%s)", node.attrs[qweb.prefix + '-if'], condition);
|
||||
}
|
||||
node.attrs[qweb.prefix + '-if'] = condition;
|
||||
}
|
||||
|
||||
function transform_qweb_template(node, fields) {
|
||||
function transformQwebTemplate(node, fields) {
|
||||
// Process modifiers
|
||||
if (node.tag && node.attrs.modifiers) {
|
||||
var modifiers = JSON.parse(node.attrs.modifiers || "{}");
|
||||
if (modifiers.invisible) {
|
||||
qweb_add_if(node, _.str.sprintf("!kanban_compute_domain(%s)", JSON.stringify(modifiers.invisible)));
|
||||
qwebAddIf(node, _.str.sprintf("!kanban_compute_domain(%s)", JSON.stringify(modifiers.invisible)));
|
||||
}
|
||||
}
|
||||
switch (node.tag) {
|
||||
@@ -108,116 +108,136 @@ function transform_qweb_template(node, fields) {
|
||||
}
|
||||
if (node.children) {
|
||||
for (var i = 0, ii = node.children.length; i < ii; i++) {
|
||||
transform_qweb_template(node.children[i], fields);
|
||||
transformQwebTemplate(node.children[i], fields);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return BasicRenderer.extend({
|
||||
className: "o_kanban_view",
|
||||
var KanbanRenderer = BasicRenderer.extend({
|
||||
className: 'o_kanban_view',
|
||||
/**
|
||||
* @override
|
||||
*/
|
||||
init: function (parent, state, params) {
|
||||
this._super.apply(this, arguments);
|
||||
|
||||
this.qweb = new QWeb(session.debug, {_s: session.origin});
|
||||
var templates = find_in_node(this.arch, function (n) { return n.tag === 'templates';});
|
||||
transform_qweb_template(templates, state.fields);
|
||||
var templates = findInNode(this.arch, function (n) { return n.tag === 'templates';});
|
||||
transformQwebTemplate(templates, state.fields);
|
||||
this.qweb.add_template(utils.json_node_to_xml(templates));
|
||||
|
||||
this.record_options = _.extend({}, params.record_options, { qweb: this.qweb });
|
||||
this.column_options = _.extend({}, params.column_options, { qweb: this.qweb });
|
||||
this.recordOptions = _.extend({}, params.record_options, { qweb: this.qweb });
|
||||
this.columnOptions = _.extend({}, params.column_options, { qweb: this.qweb });
|
||||
},
|
||||
update: function (state, fields) {
|
||||
this.fields = fields;
|
||||
return this._super(state);
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Public
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Displays the quick create record in the first column.
|
||||
*/
|
||||
addQuickCreate: function () {
|
||||
this.widgets[0].addQuickCreate();
|
||||
},
|
||||
update_record: function (record_state) {
|
||||
var is_grouped = !!this.state.groupedBy.length;
|
||||
/**
|
||||
* Removes a widget (record if ungrouped, column if grouped) from the view.
|
||||
*
|
||||
* @param {Widget} widget the instance of the widget to remove
|
||||
*/
|
||||
removeWidget: function (widget) {
|
||||
this.widgets.splice(this.widgets.indexOf(widget), 1);
|
||||
widget.destroy();
|
||||
},
|
||||
/**
|
||||
* Updates a given column with its new state.
|
||||
*
|
||||
* @param {string} localID the column id
|
||||
* @param {Object} columnState
|
||||
*
|
||||
* @returns {Deferred}
|
||||
*/
|
||||
updateColumn: function (localID, columnState) {
|
||||
var column = _.findWhere(this.widgets, {db_id: localID});
|
||||
this.widgets.splice(_.indexOf(this.widgets, column), 1); // remove column from widgets' list
|
||||
var newColumn = new KanbanColumn(this, columnState, this.columnOptions, this.recordOptions);
|
||||
this.widgets.push(newColumn);
|
||||
return newColumn.insertAfter(column.$el).then(column.destroy.bind(column));
|
||||
},
|
||||
/**
|
||||
* Updates a given record with its new state.
|
||||
*
|
||||
* @param {Object} recordState
|
||||
*/
|
||||
updateRecord: function (recordState) {
|
||||
var isGrouped = !!this.state.groupedBy.length;
|
||||
var record;
|
||||
|
||||
if (is_grouped) {
|
||||
// if grouped, this.widgets are kanban columns
|
||||
// so we need to find the kanban record inside
|
||||
if (isGrouped) {
|
||||
// if grouped, this.widgets are kanban columns so we need to find
|
||||
// the kanban record inside
|
||||
_.each(this.widgets, function (widget) {
|
||||
record = record || _.findWhere(widget.records, {db_id: record_state.id});
|
||||
record = record || _.findWhere(widget.records, {
|
||||
db_id: recordState.id,
|
||||
});
|
||||
});
|
||||
} else {
|
||||
record = _.findWhere(this.widgets, {db_id: record_state.id});
|
||||
record = _.findWhere(this.widgets, {db_id: recordState.id});
|
||||
}
|
||||
|
||||
if (record) {
|
||||
record.update(record_state);
|
||||
record.update(recordState);
|
||||
}
|
||||
},
|
||||
update_column: function (column_db_id, data) {
|
||||
var column = _.findWhere(this.widgets, {db_id: column_db_id});
|
||||
this.widgets.splice(_.indexOf(this.widgets, column), 1); // remove column from widgets' list
|
||||
var new_column = new KanbanColumn(this, data, this.column_options, this.record_options);
|
||||
this.widgets.push(new_column);
|
||||
return new_column.insertAfter(column.$el).then(column.destroy.bind(column));
|
||||
},
|
||||
_renderView: function () {
|
||||
var is_grouped = !!this.state.groupedBy.length;
|
||||
this.$el.toggleClass('o_kanban_grouped', is_grouped);
|
||||
this.$el.toggleClass('o_kanban_ungrouped', !is_grouped);
|
||||
this.$el.empty();
|
||||
|
||||
var fragment = document.createDocumentFragment();
|
||||
if (is_grouped) {
|
||||
this._renderGrouped(fragment);
|
||||
} else {
|
||||
this._render_ungrouped(fragment);
|
||||
}
|
||||
this.$el.append(fragment);
|
||||
return this._super.apply(this, arguments);
|
||||
},
|
||||
_render_ungrouped: function (fragment) {
|
||||
var self = this;
|
||||
_.each(this.state.data, function (record) {
|
||||
var kanban_record = new KanbanRecord(self, record, self.record_options);
|
||||
self.widgets.push(kanban_record);
|
||||
kanban_record.appendTo(fragment);
|
||||
});
|
||||
//--------------------------------------------------------------------------
|
||||
// Private
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
// append ghost divs to ensure that all kanban records are left aligned
|
||||
this._appendGhostDivs(fragment, 6);
|
||||
},
|
||||
/**
|
||||
* Appends empty invisible divs to a document fragment.
|
||||
* Renders empty invisible divs in a document fragment.
|
||||
*
|
||||
* @private
|
||||
* @param {DocumentFragment} fragment
|
||||
* @param {integer} nbDivs the number of divs to append
|
||||
*/
|
||||
_appendGhostDivs: function (fragment, nbDivs) {
|
||||
_renderGhostDivs: function (fragment, nbDivs) {
|
||||
for (var $ghost, i = 0; i < nbDivs; i++) {
|
||||
$ghost = $('<div>').addClass('o_kanban_record o_kanban_ghost');
|
||||
$ghost.appendTo(fragment);
|
||||
}
|
||||
},
|
||||
/**
|
||||
* Renders an grouped kanban view in a fragment.
|
||||
*
|
||||
* @private
|
||||
* @param {DocumentFragment} fragment
|
||||
*/
|
||||
_renderGrouped: function (fragment) {
|
||||
var self = this;
|
||||
var group_by_field_attrs = this.state.fields[this.state.groupedBy[0]];
|
||||
var groupByFieldAttrs = this.state.fields[this.state.groupedBy[0]];
|
||||
// Deactivate the drag'n'drop if the groupedBy field:
|
||||
// - is a date or datetime since we group by month or
|
||||
// - is readonly
|
||||
var draggable = true;
|
||||
if (group_by_field_attrs) {
|
||||
if (group_by_field_attrs.type === "date" || group_by_field_attrs.type === "datetime") {
|
||||
if (groupByFieldAttrs) {
|
||||
if (groupByFieldAttrs.type === "date" || groupByFieldAttrs.type === "datetime") {
|
||||
draggable = false;
|
||||
} else if (group_by_field_attrs.readonly !== undefined) {
|
||||
draggable = !(group_by_field_attrs.readonly);
|
||||
} else if (groupByFieldAttrs.readonly !== undefined) {
|
||||
draggable = !(groupByFieldAttrs.readonly);
|
||||
}
|
||||
}
|
||||
var grouped_by_m2o = group_by_field_attrs && (group_by_field_attrs.type === 'many2one');
|
||||
var grouped_by_field = grouped_by_m2o && group_by_field_attrs.relation;
|
||||
this.column_options = _.extend(this.column_options, {
|
||||
var groupedByM2O = groupByFieldAttrs && (groupByFieldAttrs.type === 'many2one');
|
||||
var grouped_by_field = groupedByM2O && groupByFieldAttrs.relation;
|
||||
this.columnOptions = _.extend(this.columnOptions, {
|
||||
draggable: draggable,
|
||||
grouped_by_m2o: grouped_by_m2o,
|
||||
grouped_by_m2o: groupedByM2O,
|
||||
relation: grouped_by_field,
|
||||
});
|
||||
|
||||
// Render columns
|
||||
_.each(this.state.data, function (group) {
|
||||
var column = new KanbanColumn(self, group, self.column_options, self.record_options);
|
||||
var column = new KanbanColumn(self, group, self.columnOptions, self.recordOptions);
|
||||
if (!group.value) {
|
||||
column.prependTo(fragment); // display the 'Undefined' group first
|
||||
self.widgets.unshift(column);
|
||||
@@ -247,18 +267,49 @@ return BasicRenderer.extend({
|
||||
});
|
||||
|
||||
// Column quick create
|
||||
if (this.column_options.group_creatable && grouped_by_m2o) {
|
||||
this.column_quick_create = new ColumnQuickCreate(this);
|
||||
this.column_quick_create.appendTo(fragment);
|
||||
if (this.columnOptions.group_creatable && groupedByM2O) {
|
||||
var quickCreate = new ColumnQuickCreate(this);
|
||||
quickCreate.appendTo(fragment);
|
||||
}
|
||||
},
|
||||
add_quick_create: function () {
|
||||
this.widgets[0].add_quick_create();
|
||||
/**
|
||||
* Renders an ungrouped kanban view in a fragment.
|
||||
*
|
||||
* @private
|
||||
* @param {DocumentFragment} fragment
|
||||
*/
|
||||
_renderUngrouped: function (fragment) {
|
||||
var self = this;
|
||||
_.each(this.state.data, function (record) {
|
||||
var kanbanRecord = new KanbanRecord(self, record, self.recordOptions);
|
||||
self.widgets.push(kanbanRecord);
|
||||
kanbanRecord.appendTo(fragment);
|
||||
});
|
||||
|
||||
// append ghost divs to ensure that all kanban records are left aligned
|
||||
this._renderGhostDivs(fragment, 6);
|
||||
},
|
||||
/**
|
||||
* @override
|
||||
* @private
|
||||
*/
|
||||
_renderView: function () {
|
||||
var isGrouped = !!this.state.groupedBy.length;
|
||||
this.$el.toggleClass('o_kanban_grouped', isGrouped);
|
||||
this.$el.toggleClass('o_kanban_ungrouped', !isGrouped);
|
||||
this.$el.empty();
|
||||
|
||||
var fragment = document.createDocumentFragment();
|
||||
if (isGrouped) {
|
||||
this._renderGrouped(fragment);
|
||||
} else {
|
||||
this._renderUngrouped(fragment);
|
||||
}
|
||||
this.$el.append(fragment);
|
||||
return this._super.apply(this, arguments);
|
||||
},
|
||||
remove_widget: function (widget) {
|
||||
this.widgets.splice(this.widgets.indexOf(widget), 1);
|
||||
widget.destroy();
|
||||
}
|
||||
});
|
||||
|
||||
return KanbanRenderer;
|
||||
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user