[FIX] mail: re-bind handlers on chatter buttons
When a user opens a record in a form view, the chatter is displayed. Then, if he clicks on 'Create', the chatter is removed from the DOM (there is no chatter in create mode). After saving the newly created record, the chatter is displayed again, but the same widget's instance is kept. However, when being removed from the DOM, the event handlers bound on elements of the chatter (e.g. 'New Message', 'Log a Note'... buttons) are automatically unbound. So before this rev., the buttons didn't work anymore once the form view had switched to create mode. In this commit, we detach the chatter's $el before updating the view, so that its handlers aren't unbound when the old content is replaced by the new one.
This commit is contained in:
@@ -70,6 +70,22 @@ FormRenderer.include({
|
||||
return this._super.apply(this, arguments);
|
||||
}
|
||||
},
|
||||
/**
|
||||
* Detaches the chatter before updating the $el. This is important because
|
||||
* if the view is now in create mode (edit mode with no res_id), the chatter
|
||||
* will be removed from the DOM, and its handlers will be unbound. By
|
||||
* detaching it beforehand, we ensure to keep its handlers alive so that if
|
||||
* it is re-appended later, everything will still work properly.
|
||||
*
|
||||
* @override
|
||||
* @private
|
||||
*/
|
||||
_updateView: function () {
|
||||
if (this.chatter) {
|
||||
this.chatter.$el.detach();
|
||||
}
|
||||
return this._super.apply(this, arguments);
|
||||
},
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
@@ -155,7 +155,7 @@ QUnit.test('basic rendering', function (assert) {
|
||||
});
|
||||
|
||||
QUnit.test('chatter is not rendered in mode === create', function (assert) {
|
||||
assert.expect(2);
|
||||
assert.expect(4);
|
||||
|
||||
var form = createView({
|
||||
View: FormView,
|
||||
@@ -171,11 +171,8 @@ QUnit.test('chatter is not rendered in mode === create', function (assert) {
|
||||
'</form>',
|
||||
res_id: 2,
|
||||
mockRPC: function (route, args) {
|
||||
if (route === '/mail/read_followers') {
|
||||
return $.when({
|
||||
followers: [],
|
||||
subtypes: [],
|
||||
});
|
||||
if (route === "/web/dataset/call_kw/partner/message_get_suggested_recipients") {
|
||||
return $.when({2: []});
|
||||
}
|
||||
return this._super(route, args);
|
||||
},
|
||||
@@ -191,9 +188,25 @@ QUnit.test('chatter is not rendered in mode === create', function (assert) {
|
||||
},
|
||||
});
|
||||
|
||||
assert.ok(form.$('.o_chatter').length, "there should be a chatter widget");
|
||||
assert.strictEqual(form.$('.o_chatter').length, 1,
|
||||
"chatter should be displayed");
|
||||
|
||||
form.$buttons.find('.o_form_button_create').click();
|
||||
assert.ok(!form.$('.o_chatter').length, "there should not be a chatter widget");
|
||||
|
||||
assert.strictEqual(form.$('.o_chatter').length, 0,
|
||||
"chatter should not be displayed");
|
||||
|
||||
form.$('.o_form_input').val('coucou').trigger('input');
|
||||
form.$buttons.find('.o_form_button_save').click();
|
||||
|
||||
assert.strictEqual(form.$('.o_chatter').length, 1,
|
||||
"chatter should be displayed");
|
||||
|
||||
// check if chatter buttons still work
|
||||
form.$('.o_chatter_button_new_message').click();
|
||||
assert.strictEqual(form.$('.o_chat_composer:visible').length, 1,
|
||||
"chatter should be opened");
|
||||
|
||||
form.destroy();
|
||||
});
|
||||
|
||||
|
||||
@@ -692,31 +692,44 @@ var FormRenderer = BasicRenderer.extend({
|
||||
delete this.defs;
|
||||
|
||||
return $.when.apply($, defs).then(function () {
|
||||
self.$el.html($form.contents());
|
||||
self._updateView($form.contents());
|
||||
});
|
||||
},
|
||||
/**
|
||||
* Updates the form's $el with new content.
|
||||
*
|
||||
* @private
|
||||
* @see _renderView
|
||||
* @param {JQuery} $newContent
|
||||
*/
|
||||
_updateView: function ($newContent) {
|
||||
var self = this;
|
||||
|
||||
// Necessary to allow all sub widgets to use their dimensions in
|
||||
// layout related activities, such as autoresize on fieldtexts
|
||||
core.bus.trigger('DOM_updated');
|
||||
// Set the new content of the form view, and toggle classnames
|
||||
this.$el.html($newContent);
|
||||
this.$el.toggleClass('o_form_nosheet', !this.has_sheet);
|
||||
this.$el.toggleClass('o_form_editable', this.mode === 'edit');
|
||||
this.$el.toggleClass('o_form_readonly', this.mode === 'readonly');
|
||||
|
||||
self.$el.toggleClass('o_form_nosheet', !self.has_sheet);
|
||||
self.$el.toggleClass('o_form_editable', self.mode === 'edit');
|
||||
self.$el.toggleClass('o_form_readonly', self.mode === 'readonly');
|
||||
// Attach the tooltips on the fields' label
|
||||
var focusWidget = self.defaultFocusField;
|
||||
_.each(self.allFieldWidgets[self.state.id], function (widget) {
|
||||
if (!focusWidget) {
|
||||
focusWidget = widget;
|
||||
}
|
||||
if (core.debug || widget.attrs.help || widget.field.help) {
|
||||
var idForLabel = self.idsForLabels[widget.name];
|
||||
var $label = idForLabel ? self.$('label[for=' + idForLabel + ']') : $();
|
||||
self._addFieldTooltip(widget, $label);
|
||||
}
|
||||
});
|
||||
if (focusWidget) {
|
||||
focusWidget.activate(true);
|
||||
// Necessary to allow all sub widgets to use their dimensions in
|
||||
// layout related activities, such as autoresize on fieldtexts
|
||||
core.bus.trigger('DOM_updated');
|
||||
|
||||
// Attach the tooltips on the fields' label
|
||||
var focusWidget = this.defaultFocusField;
|
||||
_.each(this.allFieldWidgets[this.state.id], function (widget) {
|
||||
if (!focusWidget) {
|
||||
focusWidget = widget;
|
||||
}
|
||||
if (core.debug || widget.attrs.help || widget.field.help) {
|
||||
var idForLabel = self.idsForLabels[widget.name];
|
||||
var $label = idForLabel ? self.$('label[for=' + idForLabel + ']') : $();
|
||||
self._addFieldTooltip(widget, $label);
|
||||
}
|
||||
});
|
||||
if (focusWidget) {
|
||||
focusWidget.activate(true);
|
||||
}
|
||||
},
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
Reference in New Issue
Block a user