summaryrefslogtreecommitdiff
path: root/addons/mail/static/src/js/services/mail_document_thread_manager.js
diff options
context:
space:
mode:
Diffstat (limited to 'addons/mail/static/src/js/services/mail_document_thread_manager.js')
-rw-r--r--addons/mail/static/src/js/services/mail_document_thread_manager.js236
1 files changed, 236 insertions, 0 deletions
diff --git a/addons/mail/static/src/js/services/mail_document_thread_manager.js b/addons/mail/static/src/js/services/mail_document_thread_manager.js
new file mode 100644
index 00000000000..40301ad724c
--- /dev/null
+++ b/addons/mail/static/src/js/services/mail_document_thread_manager.js
@@ -0,0 +1,236 @@
+odoo.define('mail.Manager.DocumentThread', function (require) {
+"use strict";
+
+var MailManager = require('mail.Manager');
+var DocumentThread = require('mail.model.DocumentThread');
+
+var session = require('web.session');
+
+/**
+ * Document Thread Manager
+ *
+ * This part of the mail manager extends the core functionnalities of mail
+ * manager with document threads, in addition to enable cross tab
+ * synchronization of document thread windows, through the local storage.
+ *
+ * Note that it assumes that the Mail Window Manager is loaded
+ */
+MailManager.include({
+ DOCUMENT_THREAD_MESSAGE_KEY: 'mail.document_threads_last_message',
+ DOCUMENT_THREAD_STATE_KEY: 'mail.document_threads_state',
+
+ start: function () {
+ this._super.apply(this, arguments);
+
+ // retrieve the open DocumentThreads from the localStorage
+ var state = this.call('local_storage', 'getItem', this.DOCUMENT_THREAD_STATE_KEY);
+ if (!state) {
+ this.call('local_storage', 'setItem', this.DOCUMENT_THREAD_STATE_KEY, '{}');
+ } else {
+ this.isReady().then(this._updateDocumentThreadWindows.bind(this, JSON.parse(state)));
+ }
+ // listen to localStorage changes to synchronize DocumentThread's
+ // windows between tabs
+ window.addEventListener('storage', this._onStorage.bind(this));
+ },
+
+ //--------------------------------------------------------------------------
+ // Public
+ //--------------------------------------------------------------------------
+
+ /**
+ * For new posted message of current user in a document thread: store it in
+ * the localStorage to make it appear on the other tabs.
+ *
+ * Note: 'addMessage' modifies the message in place (by setting the channel_id,
+ * so we must store the message in the localStorage *before* calling
+ * 'addMessage')
+ *
+ * @override
+ * @param {Object} data
+ * @param {Array} [data.author_id] [int, string] where int is server ID of
+ * the author, and string is the name of the author.
+ * @param {integer} data.id server ID of the message
+ * @param {string} [data.model] the model name of the document that this
+ * message is related to.
+ * @param {integer} [data.res_id] the ID of the document that this message
+ * is related to.
+ *
+ */
+ addMessage: function (data) {
+ var message = this.getMessage(data.id);
+ if (
+ !message &&
+ data.res_id &&
+ data.model &&
+ data.author_id &&
+ data.author_id[0] === session.partner_id
+ ) {
+ var key = this.DOCUMENT_THREAD_MESSAGE_KEY;
+ this.call('local_storage', 'setItem', key, JSON.stringify(data));
+ }
+ return this._super.apply(this, arguments);
+ },
+ /**
+ * Returns a document thread corresponding to the given model and resID.
+ *
+ * @param {string} model of the document thread, if it exists
+ * @return {integer} resID of the document thread, if it exists
+ */
+ getDocumentThread: function (model, resID) {
+ return this.getThread(model + '_' + resID);
+ },
+ /**
+ * Add a new document thread, or get if it exists already.
+ *
+ * Also, if a name is provided for the document thread, it overwrites the
+ * previous one.
+ *
+ * @param {Object} params
+ * @param {interger[]} [params.message_ids] the list of message ids linked
+ * to the document (if not given, they will be fetched before fetching the
+ * messages)
+ * @param {string} [params.name] if provided, overwrites the name of the
+ * existing document thread
+ * @param {integer} params.resID
+ * @param {string} params.resModel
+ * @return {mail.model.DocumentThread}
+ */
+ getOrAddDocumentThread: function (params) {
+ var thread = this.getDocumentThread(params.resModel, params.resID);
+ if (!thread) {
+ thread = new DocumentThread(this, {
+ messageIDs: params.messageIDs,
+ name: params.name,
+ resID: params.resID,
+ resModel: params.resModel,
+ });
+ this._threads.push(thread);
+ } else if (params.name) {
+ if ('messageIDs' in params) {
+ thread.setMessageIDs(params.messageIDs);
+ }
+ // document thread may have a change of name
+ thread.setName(params.name);
+ }
+ return thread;
+ },
+ /**
+ * Open the document thread form if discuss is open
+ *
+ * @override
+ * @param {integer|string} threadID
+ */
+ openThread: function (threadID) {
+ var thread = this.getThread(threadID);
+ if (
+ thread &&
+ thread.getType() === 'document_thread' &&
+ this._isDiscussOpen()
+ ) {
+ var resModel = thread.getDocumentModel();
+ var resID = thread.getDocumentID();
+ this._redirectToDocument(resModel, resID);
+ } else {
+ this._super.apply(this, arguments);
+ }
+ },
+ /**
+ * Updates the state of a given document thread (stored in localStorage).
+ * Garbage collects windows previously marked as 'closed' (assuming that the
+ * info has already been processed by the other tabs).
+ *
+ * @param {string} threadID ID of a document thread
+ * @param {Object} state
+ * @param {string} state.name name of the document thread
+ * @param {string} state.windowState ('closed', 'folded' or 'open')
+ */
+ updateDocumentThreadState: function (threadID, state) {
+ var item = this.call('local_storage', 'getItem', this.DOCUMENT_THREAD_STATE_KEY);
+ var states = JSON.parse(item);
+ states = _.omit(states, function (state) {
+ return state.windowState === 'closed';
+ });
+ states[threadID] = state;
+ this.call('local_storage', 'setItem',
+ this.DOCUMENT_THREAD_STATE_KEY,
+ JSON.stringify(states));
+ },
+
+ //--------------------------------------------------------------------------
+ // Private
+ //--------------------------------------------------------------------------
+
+ /**
+ * For new messages, postprocess document thread linked to this message.
+ * If there is no such document thread, create it and register its ID to
+ * the message's thread IDs.
+ *
+ * @override
+ * @private
+ * @param {mail.model.Message} message
+ */
+ _addNewMessagePostprocessThread: function (message) {
+ var resModel = message.getDocumentModel();
+ var resID = message.getDocumentID();
+ if (resModel && resModel !== 'mail.channel' && resID) {
+ this.getOrAddDocumentThread({
+ name: message.getDocumentName(),
+ resID: resID,
+ resModel: resModel,
+ });
+ }
+ this._super.apply(this, arguments);
+ },
+ /**
+ * Updates the thread windows related to document threads.
+ *
+ * @param {Object} documentThreadStates - keys are strings 'resModel_resID',
+ * and values are the state of the corresponding document thread ('open'
+ * or 'folded')
+ */
+ _updateDocumentThreadWindows: function (documentThreadStates) {
+ var self = this;
+ _.each(documentThreadStates, function (state, key) {
+ var info = key.split('_');
+ var documentThread = self.getOrAddDocumentThread({
+ name: state.name,
+ resID: parseInt(info[1]),
+ resModel: info[0],
+ });
+ if (state.windowState === 'closed') {
+ documentThread.close();
+ } else {
+ documentThread.fold(state.windowState === 'folded');
+ self.openThreadWindow(documentThread.getID(), { keepFoldState: true });
+ }
+ });
+ },
+
+ //--------------------------------------------------------------------------
+ // Handlers
+ //--------------------------------------------------------------------------
+
+ /**
+ * Called each time a localStorage key is updated.
+ *
+ * @private
+ * @param {StorageEvent} ev
+ */
+ _onStorage: function (ev) {
+ if (ev.key === this.DOCUMENT_THREAD_STATE_KEY) {
+ var state = this.call('local_storage', 'getItem', this.DOCUMENT_THREAD_STATE_KEY);
+ this._updateDocumentThreadWindows(JSON.parse(state));
+ } else if (ev.key === this.DOCUMENT_THREAD_MESSAGE_KEY) {
+ var message = this.call('local_storage', 'getItem', this.DOCUMENT_THREAD_MESSAGE_KEY);
+ if (message) {
+ this.addMessage(JSON.parse(message));
+ }
+ }
+ },
+
+});
+
+return MailManager;
+
+});