[REF] web,*: convert Kanban widgets to new style
The remaining widgets were KanbanRecord and the two quick create widgets. Now, all kanban files have been converted and refactored.
This commit is contained in:
@@ -5,7 +5,15 @@ odoo.define('hr_attendance.employee_kanban_view_handler', function(require) {
|
||||
var KanbanRecord = require('web.KanbanRecord');
|
||||
|
||||
KanbanRecord.include({
|
||||
on_card_clicked: function() {
|
||||
//--------------------------------------------------------------------------
|
||||
// Private
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @override
|
||||
* @private
|
||||
*/
|
||||
_openRecord: function () {
|
||||
if (this.modelName === 'hr.employee' && this.$el.parents('.o_hr_employee_attendance_kanban').length) {
|
||||
// needed to diffentiate : check in/out kanban view of employees <-> standard employee kanban view
|
||||
var action = {
|
||||
|
||||
@@ -4,7 +4,15 @@ odoo.define('hr_gamification.hr_gamification', function(require) {
|
||||
var KanbanRecord = require('web.KanbanRecord');
|
||||
|
||||
KanbanRecord.include({
|
||||
on_card_clicked: function() {
|
||||
//--------------------------------------------------------------------------
|
||||
// Private
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @override
|
||||
* @private
|
||||
*/
|
||||
_openRecord: function () {
|
||||
if (this.modelName === 'gamification.badge.user') {
|
||||
var action = {
|
||||
type: 'ir.actions.act_window',
|
||||
|
||||
@@ -5,7 +5,15 @@ var KanbanRecord = require('web.KanbanRecord');
|
||||
var KanbanColumn = require('web.KanbanColumn');
|
||||
|
||||
KanbanRecord.include({
|
||||
on_card_clicked: function (event) {
|
||||
//--------------------------------------------------------------------------
|
||||
// Private
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @override
|
||||
* @private
|
||||
*/
|
||||
_openRecord: function () {
|
||||
if (this.modelName === 'mail.mass_mailing.campaign') {
|
||||
this.$('.oe_mailings').click();
|
||||
} else {
|
||||
|
||||
@@ -9,14 +9,31 @@ var QWeb = core.qweb;
|
||||
var _t = core._t;
|
||||
|
||||
KanbanRecord.include({
|
||||
on_card_clicked: function () {
|
||||
//--------------------------------------------------------------------------
|
||||
// Private
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @override
|
||||
* @private
|
||||
*/
|
||||
_openRecord: function () {
|
||||
if (this.modelName === 'project.project') {
|
||||
this.$('.o_project_kanban_boxes a').first().click();
|
||||
} else {
|
||||
this._super.apply(this, arguments);
|
||||
}
|
||||
},
|
||||
on_kanban_action_clicked: function (ev) {
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Handlers
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @override
|
||||
* @private
|
||||
*/
|
||||
_onKanbanActionClicked: function (ev) {
|
||||
var self = this;
|
||||
if (this.modelName === 'project.task' && $(ev.currentTarget).data('type') === 'set_cover') {
|
||||
ev.preventDefault();
|
||||
@@ -42,9 +59,9 @@ KanbanRecord.include({
|
||||
var dialog = new Dialog(self, {
|
||||
title: _t("Set a Cover Image"),
|
||||
buttons: [{text: _t("Select"), classes: 'btn-primary', close: true, disabled: !cover_id, click: function () {
|
||||
self.update_record({data: {displayed_image_id: $imgs.filter('.o_selected').data('id')}});
|
||||
self._updateRecord({displayed_image_id: $imgs.filter('.o_selected').data('id')});
|
||||
}}, {text: _t("Remove Cover Image"), close: true, click: function () {
|
||||
self.update_record({data: {displayed_image_id: 0}});
|
||||
self._updateRecord({displayed_image_id: 0});
|
||||
}}, {text: _t("Discard"), close: true}],
|
||||
$content: $content,
|
||||
}).open();
|
||||
@@ -56,7 +73,7 @@ KanbanRecord.include({
|
||||
});
|
||||
|
||||
$content.on('dblclick', 'img', function (ev) {
|
||||
self.update_record({data: {displayed_image_id: $(ev.currentTarget).data('id')}});
|
||||
self._updateRecord({displayed_image_id: $(ev.currentTarget).data('id')});
|
||||
dialog.close();
|
||||
});
|
||||
}
|
||||
|
||||
@@ -7,10 +7,17 @@ var _t = core._t;
|
||||
|
||||
KanbanRecord.include({
|
||||
events: _.defaults({
|
||||
'click .sales_team_target_definition': 'on_sales_team_target_click',
|
||||
'click .sales_team_target_definition': '_onSalesTeamTargetClick',
|
||||
}, KanbanRecord.prototype.events),
|
||||
|
||||
on_sales_team_target_click: function(ev) {
|
||||
//--------------------------------------------------------------------------
|
||||
// Handlers
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @param {MouseEvent} ev
|
||||
*/
|
||||
_onSalesTeamTargetClick: function (ev) {
|
||||
ev.preventDefault();
|
||||
|
||||
this.$target_input = $('<input>');
|
||||
|
||||
@@ -4,7 +4,15 @@ odoo.define('sales_team.update_kanban', function (require) {
|
||||
var KanbanRecord = require('web.KanbanRecord');
|
||||
|
||||
KanbanRecord.include({
|
||||
on_card_clicked: function () {
|
||||
//--------------------------------------------------------------------------
|
||||
// Private
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @override
|
||||
* @private
|
||||
*/
|
||||
_openRecord: function () {
|
||||
if (this.modelName === 'crm.team') {
|
||||
this.$('.oe_kanban_crm_salesteams_list a').first().click();
|
||||
} else {
|
||||
|
||||
@@ -64,9 +64,7 @@ var KanbanColumn = Widget.extend({
|
||||
this.offset = 0;
|
||||
this.remaining = this.size - this.data_records.length;
|
||||
|
||||
this.record_options = _.extend(_.clone(recordOptions), {
|
||||
group_info: this.values,
|
||||
});
|
||||
this.record_options = _.clone(recordOptions);
|
||||
|
||||
if (data.options && data.options.group_by_tooltip) {
|
||||
var self = this;
|
||||
|
||||
@@ -1,37 +1,129 @@
|
||||
odoo.define('web.kanban_quick_create', function (require) {
|
||||
"use strict";
|
||||
|
||||
/**
|
||||
* This file defines two Kanban 'quick create' widgets: one to quick create
|
||||
* kanban records, and one to quick create kanban columns.
|
||||
*/
|
||||
|
||||
var Widget = require('web.Widget');
|
||||
|
||||
var RecordQuickCreate = Widget.extend({
|
||||
template: "KanbanView.QuickCreate",
|
||||
|
||||
var AbstractQuickCreate = Widget.extend({
|
||||
events: {
|
||||
'click .o_kanban_cancel': function () {
|
||||
this.cancel();
|
||||
},
|
||||
'click .o_kanban_add': function () {
|
||||
this.add_record();
|
||||
},
|
||||
'keypress input': function (event) {
|
||||
if (event.keyCode === 13) {
|
||||
this.add_record();
|
||||
}
|
||||
},
|
||||
'keydown': function (event) {
|
||||
if (event.keyCode === 27) {
|
||||
this.cancel();
|
||||
}
|
||||
},
|
||||
'mousedown .o_kanban_add': 'suppress',
|
||||
'mousedown .o_kanban_cancel': 'suppress',
|
||||
'click .o_kanban_add': '_onAddClicked',
|
||||
'click .o_kanban_cancel': '_onCancelClicked',
|
||||
'keydown': '_onKeydown',
|
||||
'keypress input': '_onKeypress',
|
||||
'mousedown .o_kanban_add': '_onMousedown',
|
||||
'mousedown .o_kanban_cancel': '_onMousedown',
|
||||
},
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Private
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Clears the input value and notify the environment that a quick create
|
||||
* has been done
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
_add: function () {
|
||||
var value = this.$input.val();
|
||||
this.$input.val('');
|
||||
if (/^\s*$/.test(value)) {
|
||||
return;
|
||||
}
|
||||
this._notifyAdd(value);
|
||||
this.$input.focus();
|
||||
},
|
||||
/**
|
||||
* Should implement what to do when the quick creation has been cancelled
|
||||
*
|
||||
* @abstract
|
||||
* @private
|
||||
*/
|
||||
_cancel: function () {
|
||||
},
|
||||
/**
|
||||
* Should implement what to do to notify the environment that a quick
|
||||
* create has been done
|
||||
*
|
||||
* @abstract
|
||||
* @private
|
||||
*/
|
||||
_notifyAdd: function (name) {
|
||||
},
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Handlers
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @param {MouseEvent} event
|
||||
*/
|
||||
_onAddClicked: function (event) {
|
||||
event.stopPropagation();
|
||||
this._add();
|
||||
},
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_onCancelClicked: function () {
|
||||
this._cancel();
|
||||
},
|
||||
/**
|
||||
* Cancels quick creation on escape keydown event
|
||||
*
|
||||
* @private
|
||||
* @param {KeyEvent} event
|
||||
*/
|
||||
_onKeydown: function (event) {
|
||||
if (event.keyCode === 27) { // escape
|
||||
this._cancel();
|
||||
}
|
||||
},
|
||||
/**
|
||||
* Validates quick creation on enter keypress event
|
||||
*
|
||||
* @private
|
||||
* @param {KeyEvent} event
|
||||
*/
|
||||
_onKeypress: function (event) {
|
||||
if (event.keyCode === 13) { // enter
|
||||
this._add();
|
||||
}
|
||||
},
|
||||
/**
|
||||
* In all browsers the 'focus/blur' event is triggered before a button's
|
||||
* 'click' (it's actually triggered by mousedown).
|
||||
* The quick create is destroyed on blur of its input but still needs
|
||||
* to create the data when the "Add" button is clicked.
|
||||
* This problem is adressed by suppressing the 'focus/blur' event from the
|
||||
* relevant buttons (Add and Cancel) entirely by preventing the browser's
|
||||
* default mousedown handler.
|
||||
*
|
||||
* @private
|
||||
* @param {MouseEvent} event
|
||||
*/
|
||||
_onMousedown: function (event) {
|
||||
event.preventDefault();
|
||||
},
|
||||
});
|
||||
|
||||
var RecordQuickCreate = AbstractQuickCreate.extend({
|
||||
template: "KanbanView.QuickCreate",
|
||||
/**
|
||||
* @override
|
||||
*/
|
||||
init: function (parent, width) {
|
||||
this._super.apply(this, arguments);
|
||||
this.width = width;
|
||||
},
|
||||
|
||||
/**
|
||||
* @override
|
||||
*/
|
||||
start: function () {
|
||||
this.$el.css({width: this.width});
|
||||
this.$input = this.$('input');
|
||||
@@ -39,66 +131,48 @@ var RecordQuickCreate = Widget.extend({
|
||||
return this._super.apply(this, arguments);
|
||||
},
|
||||
|
||||
cancel: function () {
|
||||
//--------------------------------------------------------------------------
|
||||
// Private
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Triggers up an event to cancel the quick creation
|
||||
*
|
||||
* @override
|
||||
* @private
|
||||
*/
|
||||
_cancel: function () {
|
||||
this.trigger_up('cancel_quick_create');
|
||||
},
|
||||
|
||||
add_record: function () {
|
||||
var value = this.$input.val();
|
||||
this.$input.val('');
|
||||
if (/^\s*$/.test(value)) { return; }
|
||||
/**
|
||||
* Triggers up an event to quick create a record with the given value
|
||||
*
|
||||
* @override
|
||||
* @private
|
||||
* @param {string} value
|
||||
*/
|
||||
_notifyAdd: function (value) {
|
||||
this.trigger_up('quick_create_add_record', {value: value});
|
||||
this.$input.focus();
|
||||
},
|
||||
suppress: function (e) {
|
||||
e.preventDefault();
|
||||
},
|
||||
});
|
||||
|
||||
var ColumnQuickCreate = Widget.extend({
|
||||
var ColumnQuickCreate = AbstractQuickCreate.extend({
|
||||
template: 'KanbanView.ColumnQuickCreate',
|
||||
|
||||
events: {
|
||||
'click': 'toggle',
|
||||
'click .o_kanban_add': function (event) {
|
||||
event.stopPropagation();
|
||||
this.add_column();
|
||||
},
|
||||
'click .o_kanban_cancel': function () {
|
||||
this.folded = true;
|
||||
this.update();
|
||||
},
|
||||
'click .o_kanban_quick_create': function (event) {
|
||||
event.stopPropagation();
|
||||
},
|
||||
'keypress input': function (event) {
|
||||
if (event.keyCode === 13) {
|
||||
this.add_column();
|
||||
}
|
||||
},
|
||||
'keydown': function (event) {
|
||||
if (event.keyCode === 27) {
|
||||
this.folded = true;
|
||||
this.update();
|
||||
}
|
||||
},
|
||||
'focusout': function () {
|
||||
var hasFocus = this.$(':focus').length > 0;
|
||||
if (hasFocus) { return; }
|
||||
|
||||
this.folded = true;
|
||||
this.$input.val('');
|
||||
this.update();
|
||||
},
|
||||
'mousedown .o_kanban_add': 'suppress',
|
||||
'mousedown .o_kanban_cancel': 'suppress',
|
||||
},
|
||||
|
||||
events: _.extend({}, AbstractQuickCreate.prototype.events, {
|
||||
'click': '_onClick',
|
||||
'click input': '_onInputClicked',
|
||||
'focusout': '_onFocusout',
|
||||
}),
|
||||
/**
|
||||
* @override
|
||||
*/
|
||||
init: function () {
|
||||
this._super.apply(this, arguments);
|
||||
this.folded = true;
|
||||
},
|
||||
|
||||
/**
|
||||
* @override
|
||||
*/
|
||||
start: function () {
|
||||
this.$header = this.$('.o_column_header');
|
||||
this.$quick_create = this.$('.o_kanban_quick_create');
|
||||
@@ -106,29 +180,75 @@ var ColumnQuickCreate = Widget.extend({
|
||||
return this._super.apply(this, arguments);
|
||||
},
|
||||
|
||||
toggle: function () {
|
||||
//--------------------------------------------------------------------------
|
||||
// Private
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @override
|
||||
* @private
|
||||
*/
|
||||
_cancel: function () {
|
||||
this.folded = true;
|
||||
this._update();
|
||||
},
|
||||
/**
|
||||
* Triggers up an event to quick create a column with the given value
|
||||
*
|
||||
* @override
|
||||
* @private
|
||||
* @param {string} value
|
||||
*/
|
||||
_notifyAdd: function (value) {
|
||||
this.trigger_up('quick_create_add_column', {value: value});
|
||||
},
|
||||
/**
|
||||
* Updates the rendering according to the current state
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
_update: function () {
|
||||
this.$header.toggle(this.folded);
|
||||
this.$quick_create.toggle(!this.folded);
|
||||
},
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Handlers
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @param {MouseEvent} event
|
||||
*/
|
||||
_onClick: function () {
|
||||
this.folded = !this.folded;
|
||||
this.update();
|
||||
this._update();
|
||||
if (!this.folded) {
|
||||
this.$input.focus();
|
||||
this.trigger_up('scrollTo', {selector: '.o_column_quick_create'});
|
||||
}
|
||||
},
|
||||
|
||||
update: function () {
|
||||
this.$header.toggle(this.folded);
|
||||
this.$quick_create.toggle(!this.folded);
|
||||
},
|
||||
|
||||
add_column: function () {
|
||||
var name = this.$input.val();
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_onFocusout: function () {
|
||||
var hasFocus = this.$(':focus').length > 0;
|
||||
if (hasFocus) {
|
||||
return;
|
||||
}
|
||||
this.folded = true;
|
||||
this.$input.val('');
|
||||
if (/^\s*$/.test(name)) { return; }
|
||||
this.trigger_up('quick_create_add_column', {value: name});
|
||||
this.$input.focus();
|
||||
this._update();
|
||||
},
|
||||
suppress: function (e) {
|
||||
e.preventDefault();
|
||||
/**
|
||||
* Stops the propagation of the event to prevent the quick create from
|
||||
* toggling when the user clicks in the input
|
||||
*
|
||||
* @private
|
||||
* @param {MouseEvent} event
|
||||
*/
|
||||
_onInputClicked: function (event) {
|
||||
event.stopPropagation();
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
@@ -1,86 +1,78 @@
|
||||
odoo.define('web.KanbanRecord', function (require) {
|
||||
"use strict";
|
||||
|
||||
/**
|
||||
* This file defines the KanbanRecord widget, which corresponds to a card in
|
||||
* a Kanban view.
|
||||
*/
|
||||
|
||||
var core = require('web.core');
|
||||
var Domain = require('web.Domain');
|
||||
var field_utils = require('web.field_utils');
|
||||
var framework = require('web.framework');
|
||||
var session = require('web.session');
|
||||
var utils = require('web.utils');
|
||||
var Widget = require('web.Widget');
|
||||
|
||||
var QWeb = core.qweb;
|
||||
var _t = core._t;
|
||||
var QWeb = core.qweb;
|
||||
|
||||
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',
|
||||
'click .oe_kanban_action': '_onKanbanActionClicked',
|
||||
'click .o_kanban_manage_toggle_button': '_onManageTogglerClicked',
|
||||
},
|
||||
custom_events: {
|
||||
kanban_update_record: 'update_record',
|
||||
},
|
||||
|
||||
/**
|
||||
* @override
|
||||
*/
|
||||
init: function (parent, state, options) {
|
||||
this._super(parent);
|
||||
|
||||
this.fields = state.fields;
|
||||
this.fieldAttrs = state.fieldAttrs;
|
||||
this.recordData = state.data;
|
||||
this.modelName = state.model;
|
||||
|
||||
this.options = options;
|
||||
this.editable = options.editable;
|
||||
this.deletable = options.deletable;
|
||||
this.draggable = options.draggable;
|
||||
this.read_only_mode = options.read_only_mode;
|
||||
this.group_info = options.group_info;
|
||||
this.qweb = options.qweb;
|
||||
this.sub_widgets = {};
|
||||
this.subWidgets = {};
|
||||
|
||||
this.init_content(state);
|
||||
this._setState(state);
|
||||
},
|
||||
|
||||
renderElement: function () {
|
||||
this._super();
|
||||
this.setup_color();
|
||||
this.setup_color_picker();
|
||||
this.$el.addClass('o_kanban_record');
|
||||
this.$el.data('record', this);
|
||||
if (this.$el.hasClass('oe_kanban_global_click') || this.$el.hasClass('oe_kanban_global_click_edit')) {
|
||||
this.$el.on('click', this.proxy('on_global_click'));
|
||||
}
|
||||
},
|
||||
|
||||
start: function () {
|
||||
this.add_widgets();
|
||||
this.render_m2m_tags();
|
||||
this.attach_tooltip();
|
||||
return this._super.apply(this, arguments);
|
||||
return this._super.apply(this, arguments).then(this._render.bind(this));
|
||||
},
|
||||
|
||||
init_content: function (state) {
|
||||
this.state = state;
|
||||
this.id = state.res_id;
|
||||
this.db_id = state.id;
|
||||
this.values = _.clone(state.data);
|
||||
this.record = this.transform_record(state.data);
|
||||
var qweb_context = {
|
||||
record: this.record,
|
||||
widget: this,
|
||||
read_only_mode: this.read_only_mode,
|
||||
user_context: session.user_context,
|
||||
};
|
||||
for (var p in this) {
|
||||
if (_.str.startsWith(p, 'kanban_')) {
|
||||
qweb_context[p] = _.bind(this[p], this);
|
||||
}
|
||||
}
|
||||
this.qweb_context = qweb_context;
|
||||
this.content = this.qweb.render('kanban-box', qweb_context);
|
||||
//--------------------------------------------------------------------------
|
||||
// Public
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Re-renders the record with a new state
|
||||
*
|
||||
* @param {Object} state
|
||||
*/
|
||||
update: function (state) {
|
||||
// detach the widgets because the record will empty its $el, which will
|
||||
// remove all event handlers on its descendants, and we want to keep
|
||||
// those handlers alive as we will re-use these widgets
|
||||
_.invoke(_.pluck(this.subWidgets, '$el'), 'detach');
|
||||
this._setState(state);
|
||||
this._render();
|
||||
},
|
||||
|
||||
add_widgets: function () {
|
||||
//--------------------------------------------------------------------------
|
||||
// Private
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Processes each 'field' tag and replaces it by the specified widget, if
|
||||
* any, or directly by the formatted value
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
_processFields: function () {
|
||||
var self = this;
|
||||
this.$("field").each(function () {
|
||||
var $field = $(this);
|
||||
@@ -88,10 +80,10 @@ var KanbanRecord = Widget.extend({
|
||||
var field_widget = $field.attr("widget");
|
||||
if (field_widget) {
|
||||
// a widget is specified for that field
|
||||
var widget = self.sub_widgets[field_name];
|
||||
var widget = self.subWidgets[field_name];
|
||||
if (!widget) {
|
||||
// the widget doesn't exist yet, so instanciate it
|
||||
var Widget = self.state.fieldAttrs[field_name].Widget;
|
||||
var Widget = self.fieldAttrs[field_name].Widget;
|
||||
if (Widget) {
|
||||
// some field's attrs might be record dependent (they start with
|
||||
// 't-att-') and should thus be evaluated, which is done by qweb
|
||||
@@ -101,18 +93,18 @@ var KanbanRecord = Widget.extend({
|
||||
// that dict being shared between records, we don't modify it
|
||||
// in place
|
||||
var attrs = Object.create(null);
|
||||
_.each(self.state.fieldAttrs[field_name], function (value, key) {
|
||||
_.each(self.fieldAttrs[field_name], function (value, key) {
|
||||
if (_.str.startsWith(key, 't-att-')) {
|
||||
key = key.slice(6);
|
||||
value = $field.attr(key);
|
||||
}
|
||||
attrs[key] = value;
|
||||
});
|
||||
self.state.fieldAttrs[field_name] = attrs;
|
||||
self.fieldAttrs[field_name] = attrs;
|
||||
|
||||
widget = new Widget(self, field_name, self.state, self.options);
|
||||
self.sub_widgets[field_name] = widget;
|
||||
self._set_field_display(widget, field_name);
|
||||
self.subWidgets[field_name] = widget;
|
||||
self._setFieldDisplay(widget, field_name);
|
||||
widget.replace($field);
|
||||
} else if (core.debug) {
|
||||
// the widget is not implemented
|
||||
@@ -129,92 +121,18 @@ var KanbanRecord = Widget.extend({
|
||||
// no widget specified for that field, so simply use a formatter
|
||||
// note: we could have used the widget corresponding to the field's type, but
|
||||
// it is much more efficient to use a formatter
|
||||
var field = self.state.fields[field_name];
|
||||
var recordData = self.state.data;
|
||||
var value = recordData[field_name];
|
||||
var options = { data: recordData };
|
||||
var field = self.fields[field_name];
|
||||
var value = self.recordData[field_name];
|
||||
var options = { data: self.recordData };
|
||||
var formatted_value = field_utils.format[field.type](value, field, options);
|
||||
$field.replaceWith(formatted_value);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
_set_field_display: function (widget, field_name) {
|
||||
// attribute display
|
||||
if (this.fieldAttrs[field_name].display === 'right') {
|
||||
widget.$el.addClass('pull-right');
|
||||
} else if (this.fieldAttrs[field_name].display === 'full') {
|
||||
widget.$el.addClass('o_text_block');
|
||||
}
|
||||
|
||||
// attribute bold
|
||||
if (this.fieldAttrs[field_name].bold) {
|
||||
widget.$el.addClass('o_text_bold');
|
||||
}
|
||||
},
|
||||
|
||||
render_m2m_tags: function () {
|
||||
var self = this;
|
||||
_.each(this.recordData, function (values, field_name) {
|
||||
if (self.fields[field_name].type !== 'many2many') { return; }
|
||||
var rel_ids = self.record[field_name].raw_value;
|
||||
var $m2m_tags = self.$('.o_form_field_many2manytags[name=' + field_name + ']');
|
||||
_.each(rel_ids, function (id) {
|
||||
var m2m = _.findWhere(values.data, {res_id: id}).data;
|
||||
if (typeof m2m.color !== 'undefined' && m2m.color !== 10) { // 10th color is invisible
|
||||
$('<span>')
|
||||
.addClass('o_tag o_tag_color_' + m2m.color)
|
||||
.attr('title', _.str.escapeHTML(m2m.name))
|
||||
.appendTo($m2m_tags);
|
||||
}
|
||||
});
|
||||
});
|
||||
// We use boostrap tooltips for better and faster display
|
||||
this.$('span.o_tag').tooltip({delay: {'show': 50}});
|
||||
},
|
||||
|
||||
transform_record: function (record) {
|
||||
var self = this;
|
||||
var new_record = {};
|
||||
_.each(this.state.fieldNames, function (name) {
|
||||
var value = record[name];
|
||||
var r = _.clone(self.fields[name] || {});
|
||||
|
||||
if ((r.type === 'date' || r.type === 'datetime') && value) {
|
||||
r.raw_value = value.toDate();
|
||||
} else if (r.type === 'one2many' || r.type === 'many2many') {
|
||||
r.raw_value = value.count ? value.res_ids : false;
|
||||
} else if (r.type === 'many2one' ) {
|
||||
r.raw_value = value.res_id || false;
|
||||
} else {
|
||||
r.raw_value = value;
|
||||
}
|
||||
|
||||
if (r.type) {
|
||||
var formatter = field_utils.format[r.type];
|
||||
r.value = formatter(value, self.fields[name], record, self.state);
|
||||
} else {
|
||||
r.value = value;
|
||||
}
|
||||
|
||||
new_record[name] = r;
|
||||
});
|
||||
return new_record;
|
||||
},
|
||||
|
||||
update: function (record) {
|
||||
// detach the widgets because the record will empty its $el, which will
|
||||
// remove all event handlers on its descendants, and we want to keep
|
||||
// those handlers alive as we will re-use these widgets
|
||||
_.invoke(_.pluck(this.sub_widgets, '$el'), 'detach');
|
||||
this.init_content(record);
|
||||
this.renderElement();
|
||||
this.add_widgets();
|
||||
this.render_m2m_tags();
|
||||
this.attach_tooltip();
|
||||
},
|
||||
|
||||
attach_tooltip: function () {
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_attachTooltip: function () {
|
||||
var self = this;
|
||||
this.$('[tooltip]').each(function () {
|
||||
var $el = $(this);
|
||||
@@ -227,30 +145,33 @@ var KanbanRecord = Widget.extend({
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
kanban_image: function (model, field, id, cache, options) {
|
||||
options = options || {};
|
||||
var url;
|
||||
if (this.record[field] && this.record[field].value && !utils.is_bin_size(this.record[field].value)) {
|
||||
url = 'data:image/png;base64,' + this.record[field].value;
|
||||
} else if (this.record[field] && ! this.record[field].value) {
|
||||
url = "/web/static/src/img/placeholder.png";
|
||||
} else {
|
||||
if (_.isArray(id)) { id = id[0]; }
|
||||
if (!id) { id = undefined; }
|
||||
if (options.preview_image)
|
||||
field = options.preview_image;
|
||||
var unique = this.record.__last_update && this.record.__last_update.value.replace(/[^0-9]/g, '');
|
||||
url = session.url('/web/image', {model: model, field: field, id: id, unique: unique});
|
||||
if (cache !== undefined) {
|
||||
// Set the cache duration in seconds.
|
||||
url += '&cache=' + parseInt(cache, 10);
|
||||
}
|
||||
}
|
||||
return url;
|
||||
/**
|
||||
* @private
|
||||
* @param {string} d a stringified domain
|
||||
* @returns {boolean} the domain evaluted with the current values
|
||||
*/
|
||||
_computeDomain: function (d) {
|
||||
return new Domain(d).compute(this.recordData);
|
||||
},
|
||||
|
||||
kanban_getcolor: function (variable) {
|
||||
/**
|
||||
* Generates the color classname from a given variable
|
||||
*
|
||||
* @private
|
||||
* @param {number || string} variable
|
||||
* @return {string} the classname
|
||||
*/
|
||||
_getColorClassname: function (variable) {
|
||||
var color = this._getColorID(variable);
|
||||
return 'oe_kanban_color_' + color;
|
||||
},
|
||||
/**
|
||||
* Computes a color id between 0 and 10 from a given value
|
||||
*
|
||||
* @private
|
||||
* @param {number || string} variable
|
||||
* @returns {integer} the color id
|
||||
*/
|
||||
_getColorID: function (variable) {
|
||||
if (typeof(variable) === 'number') {
|
||||
return Math.round(variable) % 10;
|
||||
}
|
||||
@@ -263,23 +184,234 @@ var KanbanRecord = Widget.extend({
|
||||
}
|
||||
return 0;
|
||||
},
|
||||
/**
|
||||
* @private
|
||||
* @param {string} model the name of the model
|
||||
* @param {string} field the name of the field
|
||||
* @param {integer} id the id of the resource
|
||||
* @param {integer} cache the cache duration, in seconds
|
||||
* @param {Object} options
|
||||
* @returns {string} the url of the image
|
||||
*/
|
||||
_getImageURL: function (model, field, id, cache, options) {
|
||||
options = options || {};
|
||||
var url;
|
||||
if (this.record[field] && this.record[field].value && !utils.is_bin_size(this.record[field].value)) {
|
||||
url = 'data:image/png;base64,' + this.record[field].value;
|
||||
} else if (this.record[field] && ! this.record[field].value) {
|
||||
url = "/web/static/src/img/placeholder.png";
|
||||
} else {
|
||||
if (_.isArray(id)) { id = id[0]; }
|
||||
if (!id) { id = undefined; }
|
||||
if (options.preview_image)
|
||||
field = options.preview_image;
|
||||
var unique = this.record.__last_update && this.record.__last_update.value.replace(/[^0-9]/g, '');
|
||||
var session = this.getSession();
|
||||
url = session.url('/web/image', {model: model, field: field, id: id, unique: unique});
|
||||
if (cache !== undefined) {
|
||||
// Set the cache duration in seconds.
|
||||
url += '&cache=' + parseInt(cache, 10);
|
||||
}
|
||||
}
|
||||
return url;
|
||||
},
|
||||
/**
|
||||
* Triggers up an event to open the record
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
_openRecord: function () {
|
||||
var editMode = this.$el.hasClass('oe_kanban_global_click_edit');
|
||||
this.trigger_up('open_record', {
|
||||
id: this.db_id,
|
||||
mode: editMode ? 'edit' : 'readonly',
|
||||
});
|
||||
},
|
||||
/**
|
||||
* Renders the record
|
||||
*/
|
||||
_render: function () {
|
||||
this.replaceElement(this.qweb.render('kanban-box', this.qweb_context));
|
||||
this.$el.addClass('o_kanban_record');
|
||||
this.$el.data('record', this);
|
||||
if (this.$el.hasClass('oe_kanban_global_click') ||
|
||||
this.$el.hasClass('oe_kanban_global_click_edit')) {
|
||||
this.$el.on('click', this._onGlobalClick.bind(this));
|
||||
}
|
||||
this._processFields();
|
||||
this._setupColor();
|
||||
this._setupColorPicker();
|
||||
this._renderM2MTags();
|
||||
this._attachTooltip();
|
||||
},
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_renderM2MTags: function () {
|
||||
var self = this;
|
||||
_.each(this.recordData, function (values, field_name) {
|
||||
if (self.fields[field_name].type !== 'many2many') { return; }
|
||||
var rel_ids = self.record[field_name].raw_value;
|
||||
var $m2m_tags = self.$('.o_form_field_many2manytags[name=' + field_name + ']');
|
||||
_.each(rel_ids, function (id) {
|
||||
var m2m = _.findWhere(values.data, {res_id: id}).data;
|
||||
if (typeof m2m.color !== 'undefined' && m2m.color !== 10) { // 10th color is invisible
|
||||
$('<span>')
|
||||
.addClass('o_tag o_tag_color_' + m2m.color)
|
||||
.attr('title', _.str.escapeHTML(m2m.display_name))
|
||||
.appendTo($m2m_tags);
|
||||
}
|
||||
});
|
||||
});
|
||||
// We use boostrap tooltips for better and faster display
|
||||
this.$('span.o_tag').tooltip({delay: {'show': 50}});
|
||||
},
|
||||
/**
|
||||
* Sets particular classnames on a field widget's $el according to the
|
||||
* field's attrs (display or bold attributes)
|
||||
*
|
||||
* @private
|
||||
* @param {Widget} widget a field widget
|
||||
* @param {string} fieldName
|
||||
*/
|
||||
_setFieldDisplay: function (widget, fieldName) {
|
||||
// attribute display
|
||||
if (this.fieldAttrs[fieldName].display === 'right') {
|
||||
widget.$el.addClass('pull-right');
|
||||
} else if (this.fieldAttrs[fieldName].display === 'full') {
|
||||
widget.$el.addClass('o_text_block');
|
||||
}
|
||||
|
||||
kanban_color: function (variable) {
|
||||
var color = this.kanban_getcolor(variable);
|
||||
return 'oe_kanban_color_' + color;
|
||||
// attribute bold
|
||||
if (this.fieldAttrs[fieldName].bold) {
|
||||
widget.$el.addClass('o_text_bold');
|
||||
}
|
||||
},
|
||||
/**
|
||||
* Sets internal values of the kanban record according to the given state
|
||||
*
|
||||
* @private
|
||||
* @param {Object} recordState
|
||||
*/
|
||||
_setState: function (recordState) {
|
||||
this.state = recordState;
|
||||
this.id = recordState.res_id;
|
||||
this.db_id = recordState.id;
|
||||
this.recordData = recordState.data;
|
||||
this.record = this._transformRecord(recordState.data);
|
||||
this.qweb_context = {
|
||||
kanban_image: this._getImageURL.bind(this),
|
||||
kanban_color: this._getColorClassname.bind(this),
|
||||
kanban_getcolor: this._getColorID.bind(this),
|
||||
kanban_compute_domain: this._computeDomain.bind(this),
|
||||
read_only_mode: this.read_only_mode,
|
||||
record: this.record,
|
||||
user_context: this.getSession().user_context,
|
||||
widget: this,
|
||||
};
|
||||
},
|
||||
/**
|
||||
* If an attribute `color` is set on the kanban record, adds the
|
||||
* corresponding color classname.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
_setupColor: function () {
|
||||
var color_field = this.$el.attr('color');
|
||||
if (color_field && color_field in this.fields) {
|
||||
var colorClass = this._getColorClassname(this.recordData[color_field]);
|
||||
this.$el.addClass(colorClass);
|
||||
}
|
||||
},
|
||||
/**
|
||||
* Renders the color picker in the kanban record, and binds the event handler
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
_setupColorPicker: function () {
|
||||
var $colorpicker = this.$('ul.oe_kanban_colorpicker');
|
||||
if (!$colorpicker.length) {
|
||||
return;
|
||||
}
|
||||
$colorpicker.html(QWeb.render('KanbanColorPicker'));
|
||||
$colorpicker.on('click', 'a', this._onColorChanged.bind(this));
|
||||
},
|
||||
/**
|
||||
* Builds an object containing the formatted record data used in the
|
||||
* template
|
||||
*
|
||||
* @private
|
||||
* @param {Object} recordData
|
||||
* @returns {Object} transformed record data
|
||||
*/
|
||||
_transformRecord: function (recordData) {
|
||||
var self = this;
|
||||
var new_record = {};
|
||||
_.each(this.state.fieldNames, function (name) {
|
||||
var value = recordData[name];
|
||||
var r = _.clone(self.fields[name] || {});
|
||||
|
||||
if ((r.type === 'date' || r.type === 'datetime') && value) {
|
||||
r.raw_value = value.toDate();
|
||||
} else if (r.type === 'one2many' || r.type === 'many2many') {
|
||||
r.raw_value = value.count ? value.res_ids : false;
|
||||
} else if (r.type === 'many2one' ) {
|
||||
r.raw_value = value && value.res_id || false;
|
||||
} else {
|
||||
r.raw_value = value;
|
||||
}
|
||||
|
||||
if (r.type) {
|
||||
var formatter = field_utils.format[r.type];
|
||||
r.value = formatter(value, self.fields[name], recordData, self.state);
|
||||
} else {
|
||||
r.value = value;
|
||||
}
|
||||
|
||||
new_record[name] = r;
|
||||
});
|
||||
return new_record;
|
||||
},
|
||||
/**
|
||||
* Notifies the controller that the record has changed
|
||||
*
|
||||
* @private
|
||||
* @param {Object} data the new values
|
||||
*/
|
||||
_updateRecord: function (data) {
|
||||
this.trigger_up('kanban_record_update', data);
|
||||
},
|
||||
|
||||
on_global_click: function (ev) {
|
||||
if ($(ev.target).parents('.o_dropdown_kanban').length) {
|
||||
//--------------------------------------------------------------------------
|
||||
// Handlers
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @param {MouseEvent} event
|
||||
*/
|
||||
_onColorChanged: function (event) {
|
||||
event.preventDefault();
|
||||
var data = {};
|
||||
var color_field = $(event.delegateTarget).data('field') || 'color';
|
||||
data[color_field] = $(event.currentTarget).data('color');
|
||||
this.trigger_up('kanban_record_update', data);
|
||||
},
|
||||
/**
|
||||
* @private
|
||||
* @param {MouseEvent} event
|
||||
*/
|
||||
_onGlobalClick: function (event) {
|
||||
if ($(event.target).parents('.o_dropdown_kanban').length) {
|
||||
return;
|
||||
}
|
||||
var trigger = true;
|
||||
var elem = ev.target;
|
||||
var elem = event.target;
|
||||
var ischild = true;
|
||||
var children = [];
|
||||
while (elem) {
|
||||
var events = $._data(elem, 'events');
|
||||
if (elem === ev.currentTarget) {
|
||||
if (elem === event.currentTarget) {
|
||||
ischild = false;
|
||||
}
|
||||
var test_event = events && events.click && (events.click.length > 1 || events.click[0].namespace !== "tooltip");
|
||||
@@ -306,35 +438,17 @@ var KanbanRecord = Widget.extend({
|
||||
elem = elem.parentElement;
|
||||
}
|
||||
if (trigger) {
|
||||
this.on_card_clicked(ev);
|
||||
this._openRecord();
|
||||
}
|
||||
},
|
||||
|
||||
/* actions when user click on the block with a specific class
|
||||
* open on normal view : oe_kanban_global_click
|
||||
* open on form/edit view : oe_kanban_global_click_edit
|
||||
/**
|
||||
* @private
|
||||
* @param {MouseEvent} event
|
||||
*/
|
||||
on_card_clicked: function () {
|
||||
if (this.$el.hasClass('oe_kanban_global_click_edit') && this.$el.data('routing')) {
|
||||
framework.redirect(this.$el.data('routing') + "/" + this.id);
|
||||
} else if (this.$el.hasClass('oe_kanban_global_click_edit')) {
|
||||
this.trigger_up('edit_record', {id: this.db_id});
|
||||
} else {
|
||||
this.trigger_up('open_record', {id: this.db_id});
|
||||
}
|
||||
},
|
||||
|
||||
toggle_manage_pane: function (event){
|
||||
_onKanbanActionClicked: function (event) {
|
||||
event.preventDefault();
|
||||
this.$('.o_kanban_card_content').toggleClass('o_visible o_invisible');
|
||||
this.$('.o_kanban_card_manage_pane').toggleClass('o_visible o_invisible');
|
||||
this.$('.o_kanban_manage_button_section').toggleClass(this.kanban_color(this.values['color'] || 0));
|
||||
},
|
||||
|
||||
on_kanban_action_clicked: function (ev) {
|
||||
ev.preventDefault();
|
||||
|
||||
var $action = $(ev.currentTarget);
|
||||
var $action = $(event.currentTarget);
|
||||
var type = $action.data('type') || 'button';
|
||||
|
||||
switch (type) {
|
||||
@@ -358,44 +472,19 @@ var KanbanRecord = Widget.extend({
|
||||
this.do_warn("Kanban: no action for type : " + type);
|
||||
}
|
||||
},
|
||||
|
||||
kanban_compute_domain: function (d) {
|
||||
return new Domain(d).compute(this.values);
|
||||
},
|
||||
|
||||
update_record: function (event) {
|
||||
this.trigger_up('kanban_record_update', event.data);
|
||||
},
|
||||
|
||||
/*
|
||||
* If an attribute `color` is set on the kanban record,
|
||||
* this will add the corresponding color class.
|
||||
/**
|
||||
* Toggles the configuration panel of the record
|
||||
*
|
||||
* @private
|
||||
* @param {MouseEvent} event
|
||||
*/
|
||||
setup_color: function () {
|
||||
var color_field = this.$el.attr('color');
|
||||
if (color_field && color_field in this.fields) {
|
||||
this.$el.addClass(this.kanban_color(this.values[color_field]));
|
||||
}
|
||||
_onManageTogglerClicked: function (event) {
|
||||
event.preventDefault();
|
||||
this.$('.o_kanban_card_content').toggleClass('o_visible o_invisible');
|
||||
this.$('.o_kanban_card_manage_pane').toggleClass('o_visible o_invisible');
|
||||
var colorClass = this._getColorClassname(this.recordData.color || 0);
|
||||
this.$('.o_kanban_manage_button_section').toggleClass(colorClass);
|
||||
},
|
||||
|
||||
setup_color_picker: function () {
|
||||
var self = this;
|
||||
var $colorpicker = this.$('ul.oe_kanban_colorpicker');
|
||||
if (!$colorpicker.length) {
|
||||
return;
|
||||
}
|
||||
$colorpicker.html(QWeb.render('KanbanColorPicker', {
|
||||
widget: this
|
||||
}));
|
||||
$colorpicker.on('click', 'a', function (ev) {
|
||||
ev.preventDefault();
|
||||
var color_field = $colorpicker.data('field') || 'color';
|
||||
var data = {};
|
||||
data[color_field] = $(this).data('color');
|
||||
self.trigger_up('kanban_record_update', data);
|
||||
});
|
||||
},
|
||||
|
||||
});
|
||||
|
||||
return KanbanRecord;
|
||||
|
||||
@@ -55,10 +55,6 @@
|
||||
</div>
|
||||
</t>
|
||||
|
||||
<t t-name="KanbanView.record">
|
||||
<t t-raw="widget.content"/>
|
||||
</t>
|
||||
|
||||
<t t-name="KanbanView.QuickCreate">
|
||||
<div class="o_kanban_quick_create">
|
||||
<input type="text" placeholder="Add"/>
|
||||
|
||||
Reference in New Issue
Block a user