mirror of https://github.com/OCA/web.git
[MIG] web_send_message_popup: Migration to 18.0
parent
72465a3c4e
commit
b9914a9bcf
|
@ -2,14 +2,12 @@
|
||||||
# License AGPL-3.0 or later (http://gnu.org/licenses/agpl).
|
# License AGPL-3.0 or later (http://gnu.org/licenses/agpl).
|
||||||
{
|
{
|
||||||
"name": "Web Send Message as Popup",
|
"name": "Web Send Message as Popup",
|
||||||
"version": "16.0.1.0.0",
|
"version": "18.0.1.0.0",
|
||||||
"author": "Camptocamp, Odoo Community Association (OCA)",
|
"author": "Camptocamp, Odoo Community Association (OCA)",
|
||||||
"maintainer": "Camptocamp",
|
"maintainer": "Camptocamp",
|
||||||
"license": "AGPL-3",
|
"license": "AGPL-3",
|
||||||
"category": "Hidden",
|
"category": "Hidden",
|
||||||
"depends": ["web", "mail"],
|
"depends": ["web", "mail"],
|
||||||
"website": "https://github.com/OCA/web",
|
"website": "https://github.com/OCA/web",
|
||||||
"assets": {
|
"assets": {"web.assets_backend": ["web_send_message_popup/static/src/**/*.js"]},
|
||||||
"web.assets_backend": ["web_send_message_popup/static/src/models/**/*.js"]
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,183 @@
|
||||||
|
import {EventBus, markup, toRaw} from "@odoo/owl";
|
||||||
|
import {Chatter} from "@mail/chatter/web_portal/chatter";
|
||||||
|
import {SIGNATURE_CLASS} from "@html_editor/main/signature_plugin";
|
||||||
|
import {_t} from "@web/core/l10n/translation";
|
||||||
|
import {browser} from "@web/core/browser/browser";
|
||||||
|
import {childNodes} from "@html_editor/utils/dom_traversal";
|
||||||
|
import {parseHTML} from "@html_editor/utils/html";
|
||||||
|
import {patch} from "@web/core/utils/patch";
|
||||||
|
import {prettifyMessageContent} from "@mail/utils/common/format";
|
||||||
|
import {renderToElement} from "@web/core/utils/render";
|
||||||
|
import {rpc} from "@web/core/network/rpc";
|
||||||
|
import {wrapInlinesInBlocks} from "@html_editor/utils/dom";
|
||||||
|
|
||||||
|
patch(Chatter.prototype, {
|
||||||
|
setup() {
|
||||||
|
super.setup(...arguments);
|
||||||
|
this.fullComposerBus = new EventBus();
|
||||||
|
this.isFullComposerOpen = false;
|
||||||
|
},
|
||||||
|
toggleComposer(mode = false) {
|
||||||
|
if (mode === "message") {
|
||||||
|
this.closeSearch();
|
||||||
|
this.state.composerType = false;
|
||||||
|
if (!this.state.thread.id) {
|
||||||
|
this.props.saveRecord?.();
|
||||||
|
}
|
||||||
|
this.openFullComposer();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
return super.toggleComposer(...arguments);
|
||||||
|
},
|
||||||
|
// A rough composer function copy of `onClickFullComposer`
|
||||||
|
async openFullComposer() {
|
||||||
|
const newPartners = this.state.thread.suggestedRecipients.filter(
|
||||||
|
(recipient) => recipient.checked && !recipient.persona
|
||||||
|
);
|
||||||
|
if (newPartners.length) {
|
||||||
|
const recipientEmails = [];
|
||||||
|
const recipientAdditionalValues = {};
|
||||||
|
newPartners.forEach((recipient) => {
|
||||||
|
recipientEmails.push(recipient.email);
|
||||||
|
recipientAdditionalValues[recipient.email] =
|
||||||
|
recipient.create_values || {};
|
||||||
|
});
|
||||||
|
const partners = await rpc("/mail/partner/from_email", {
|
||||||
|
emails: recipientEmails,
|
||||||
|
additional_values: recipientAdditionalValues,
|
||||||
|
});
|
||||||
|
for (const index in partners) {
|
||||||
|
const partnerData = partners[index];
|
||||||
|
const persona = this.store.Persona.insert({
|
||||||
|
...partnerData,
|
||||||
|
type: "partner",
|
||||||
|
});
|
||||||
|
const email = recipientEmails[index];
|
||||||
|
const recipient = this.state.thread.suggestedRecipients.find(
|
||||||
|
(rec) => rec.email === email
|
||||||
|
);
|
||||||
|
Object.assign(recipient, {persona});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const body = this.state.thread.composer.text;
|
||||||
|
const validMentions = this.store.getMentionsFromText(body, {
|
||||||
|
mentionedChannels: this.state.thread.composer.mentionedChannels,
|
||||||
|
mentionedPartners: this.state.thread.composer.mentionedPartners,
|
||||||
|
});
|
||||||
|
let default_body = await prettifyMessageContent(body, validMentions);
|
||||||
|
if (!default_body) {
|
||||||
|
const composer = toRaw(this.state.thread.composer);
|
||||||
|
composer.emailAddSignature = true;
|
||||||
|
}
|
||||||
|
default_body = this.formatDefaultBodyForFullComposer(
|
||||||
|
default_body,
|
||||||
|
this.state.thread.composer.emailAddSignature
|
||||||
|
? markup(this.store.self.signature)
|
||||||
|
: ""
|
||||||
|
);
|
||||||
|
const action = {
|
||||||
|
name: _t("Compose Email"),
|
||||||
|
type: "ir.actions.act_window",
|
||||||
|
res_model: "mail.compose.message",
|
||||||
|
view_mode: "form",
|
||||||
|
views: [[false, "form"]],
|
||||||
|
target: "new",
|
||||||
|
context: {
|
||||||
|
default_attachment_ids: this.state.thread.composer.attachments.map(
|
||||||
|
(attachment) => attachment.id
|
||||||
|
),
|
||||||
|
default_body,
|
||||||
|
default_email_add_signature: false,
|
||||||
|
default_model: this.state.thread.model,
|
||||||
|
default_partner_ids: this.state.thread.suggestedRecipients
|
||||||
|
.filter((recipient) => recipient.checked)
|
||||||
|
.map((recipient) => recipient.persona.id),
|
||||||
|
default_res_ids: [this.state.thread.id],
|
||||||
|
default_subtype_xmlid: "mail.mt_comment",
|
||||||
|
mail_post_autofollow: this.state.thread.hasWriteAccess,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
const options = {
|
||||||
|
onClose: (...args) => {
|
||||||
|
const accidentalDiscard = !args.length;
|
||||||
|
const isDiscard = accidentalDiscard || args[0]?.special;
|
||||||
|
if (!isDiscard && this.state.thread.model === "mail.box") {
|
||||||
|
this.notifySendFromMailbox();
|
||||||
|
}
|
||||||
|
if (accidentalDiscard) {
|
||||||
|
this.fullComposerBus.trigger("ACCIDENTAL_DISCARD", {
|
||||||
|
onAccidentalDiscard: (isEmpty) => {
|
||||||
|
if (!isEmpty) {
|
||||||
|
this.saveContent();
|
||||||
|
this.restoreContent();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
this.clear();
|
||||||
|
}
|
||||||
|
this.onCloseFullComposerCallback();
|
||||||
|
this.isFullComposerOpen = false;
|
||||||
|
this.fullComposerBus = new EventBus();
|
||||||
|
},
|
||||||
|
props: {fullComposerBus: this.fullComposerBus},
|
||||||
|
};
|
||||||
|
await this.env.services.action.doAction(action, options);
|
||||||
|
this.isFullComposerOpen = true;
|
||||||
|
},
|
||||||
|
// Method copied not from the composer file but the composer_patch one
|
||||||
|
formatDefaultBodyForFullComposer(defaultBody, signature = "") {
|
||||||
|
const fragment = parseHTML(document, defaultBody);
|
||||||
|
if (!fragment.firstChild) {
|
||||||
|
fragment.append(document.createElement("BR"));
|
||||||
|
}
|
||||||
|
if (signature) {
|
||||||
|
const signatureEl = renderToElement("html_editor.Signature", {
|
||||||
|
signature,
|
||||||
|
signatureClass: SIGNATURE_CLASS,
|
||||||
|
});
|
||||||
|
fragment.append(signatureEl);
|
||||||
|
}
|
||||||
|
const container = document.createElement("DIV");
|
||||||
|
container.append(...childNodes(fragment));
|
||||||
|
wrapInlinesInBlocks(container, {baseContainerNodeName: "DIV"});
|
||||||
|
return container.innerHTML;
|
||||||
|
},
|
||||||
|
// Copied and modified methods from composer
|
||||||
|
notifySendFromMailbox() {
|
||||||
|
this.env.services.notification.add(
|
||||||
|
_t('Message posted on "%s"', this.state.thread.displayName),
|
||||||
|
{type: "info"}
|
||||||
|
);
|
||||||
|
},
|
||||||
|
saveContent() {
|
||||||
|
const composer = toRaw(this.state.thread.composer);
|
||||||
|
const onSaveContent = (text, emailAddSignature) => {
|
||||||
|
browser.localStorage.setItem(
|
||||||
|
composer.localId,
|
||||||
|
JSON.stringify({emailAddSignature, text})
|
||||||
|
);
|
||||||
|
};
|
||||||
|
if (this.isFullComposerOpen) {
|
||||||
|
this.fullComposerBus.trigger("SAVE_CONTENT", {onSaveContent});
|
||||||
|
} else {
|
||||||
|
onSaveContent(composer.text, true);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
restoreContent() {
|
||||||
|
const composer = toRaw(this.state.thread.composer);
|
||||||
|
try {
|
||||||
|
const config = JSON.parse(browser.localStorage.getItem(composer.localId));
|
||||||
|
if (config.text) {
|
||||||
|
composer.emailAddSignature = config.emailAddSignature;
|
||||||
|
composer.text = config.text;
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
browser.localStorage.removeItem(composer.localId);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
clear() {
|
||||||
|
this.state.thread.composer.clear();
|
||||||
|
browser.localStorage.removeItem(this.state.thread.composer.localId);
|
||||||
|
},
|
||||||
|
});
|
|
@ -1,62 +0,0 @@
|
||||||
/** @odoo-module **/
|
|
||||||
|
|
||||||
import {clear} from "@mail/model/model_field_command";
|
|
||||||
import {escapeAndCompactTextContent} from "@mail/js/utils";
|
|
||||||
import {registerPatch} from "@mail/model/model_core";
|
|
||||||
|
|
||||||
registerPatch({
|
|
||||||
name: "Chatter",
|
|
||||||
recordMethods: {
|
|
||||||
// Fn overwrite
|
|
||||||
onClickSendMessage() {
|
|
||||||
if (this.composerView) {
|
|
||||||
// Change `isLog` to false since this should only be possible when you
|
|
||||||
// press "Log Note" first, otherwise this won't hurt.
|
|
||||||
this.composerView.composer.update({isLog: false});
|
|
||||||
// Open the full composer with `composerView` because it carries through
|
|
||||||
// the composer options.
|
|
||||||
this.composerView.openFullComposer();
|
|
||||||
// Clear the `composerView` since we don't need it no more.
|
|
||||||
this.update({composerView: clear()});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.openFullComposer();
|
|
||||||
},
|
|
||||||
async openFullComposer() {
|
|
||||||
// Rough copy of composer view function `openFullComposer`.
|
|
||||||
// Get composer from thread.
|
|
||||||
// We access data from the composer since history still is saved there.
|
|
||||||
// e.g. open and close "Log note".
|
|
||||||
const composer = this.thread.composer;
|
|
||||||
const context = {
|
|
||||||
default_attachment_ids: composer.attachments.map((att) => att.id),
|
|
||||||
default_body: escapeAndCompactTextContent(composer.textInputContent),
|
|
||||||
default_is_log: false,
|
|
||||||
default_model: this.threadModel,
|
|
||||||
default_partner_ids: composer.recipients.map((partner) => partner.id),
|
|
||||||
default_res_id: this.threadId,
|
|
||||||
mail_post_autofollow: this.thread.hasWriteAccess,
|
|
||||||
};
|
|
||||||
const action = {
|
|
||||||
type: "ir.actions.act_window",
|
|
||||||
name: this.env._t("Compose Email"),
|
|
||||||
res_model: "mail.compose.message",
|
|
||||||
view_mode: "form",
|
|
||||||
views: [[false, "form"]],
|
|
||||||
target: "new",
|
|
||||||
context,
|
|
||||||
};
|
|
||||||
const options = {
|
|
||||||
on_close: () => {
|
|
||||||
if (composer.exists()) {
|
|
||||||
composer._reset();
|
|
||||||
if (composer.activeThread) {
|
|
||||||
composer.activeThread.fetchData(["messages"]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
};
|
|
||||||
await this.env.services.action.doAction(action, options);
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
Loading…
Reference in New Issue