summaryrefslogtreecommitdiff
path: root/addons/mail/static/src/js/thread_windows/abstract_thread_window.js
diff options
context:
space:
mode:
authorAlexandre Kühn <aku@odoo.com>2018-08-11 20:30:51 +0200
committerAlexandre Kühn <aku@odoo.com>2018-08-13 14:17:27 +0200
commitf2302dfb27dd7f6a0dee7c65ab75b62a01706264 (patch)
treed58fef9e2e8a5b98c0680f28fc92e24992236029 /addons/mail/static/src/js/thread_windows/abstract_thread_window.js
parent3de97f168956a7c22c3af6b72950cf28554f4139 (diff)
[REF][FIX] mail, im_livechat: various improvements (JS)
This commit makes a lot of small improvements of the JS of mail and related modules. A. Mail Manager --------------- im_support: - [REF] Slightly more robust way to determine a support message, so that it more reliably falls back on default kind of message (i.e. support channel UUID should be clearly set). mail: - [REF] Improved method names for readability purposes. Some examples: - `fetchFromServer` becomes `fetchMailStateFromServer` - `_initialize{*}` becomes `_update{*}FromServer` - `_isModerator` becomes `_isMyselfModerator` - [REF] Use 'template' pattern design to make Include on Mail Manager much more robust. In particular, the flow is always as follow: 1. Initialize internal state. 2. Listen on buses. 3. Fetch mail data from server. - [REF] Improved workflow for thread window workflow (Shorter & more readable). B. Mail Tests ------------- - [REF] Thread Window Tests crashes with clean message when there are some thread windows open before running the tests. C. (Model) Message ------------------ - [REF] Improved method names for readability purposes (e.g. `isAuthor` becomes `isMyselfAuthor`). D. (Model) Thread ----------------- - [REF] Improved `init` parameters on each kind of thread. - [REF] 'Thread With Cache' has been renamed to 'Searchable Thread': it embraces all kinds of threads that can be used with the search view. - [REF] 'DM' has been renamed to 'DM Chat' (for clarity). - [IMP] New Livechat model in the backend. - [REF] No more direct instances of the Channel class: public and private channels are now 'Multi-User' channels, while DM Chat and Livechat are 'Two-User' channels: This change has been made so that instances of classes always have direct classes as "leaf" in the Class modeling. It eases making changes to a certain model without being too constrained by another model. - [REF] As a consequence of above changed, the method `isChat` has been renamed to `isTwoUserThread`. This is to avoid confusion with the terminology 'chat', which is more like a shortcut for 'quick real- time conversation'. In other words, the property of 'chat' depends of the way to interact on a thread, not of the intrinsic type of the thread. Still, some parts have kept the terminology 'chat', such as in the systray messagin menu. - [IMP] Added `message_added` and `message_posted` hooks, which may be useful to easily hook on those events. E. Thread Widget ---------------- - [REF] Now uses a `mail.model.AbstractThread` for the rendering of a thread, instead of a list of `{mail.model.AbstractMessage}`. - [FIX] Stick thread scroll height to bottom on new rendering, if it was previously at the bottom of the thread. - [REF] Option ORDER has its meaning changed: it now refers to the chronological order of messages in the thread, in which DESC means 'from top to bottom', while ASC means 'from bottom to top'. - [REF] Improved doc on templates, in particular with the option `ORDER`. F. Thread Window ---------------- - [REF] Moved more logic to thread windows, which were previously in Mail Window Manager. - [REF] Now hides the thread widget attribute. So instead of `threadWindow.threadWidget.isAtBottom()`, it uses `threadWindow.isAtBottom()`. - [FIX] New received messages when not having focus on Odoo tab should always make the corresponding thread windows "passive" (i.e. windows that keep threads unread until click on them). - [FIX] Blank thread window (i.e. 'New message' TW) correctly opens Discuss with 'Inbox' when clicking on 'Expand' Button in the title - [FIX] Do not display the composer for channels with property 'mass-mailing' set in thread windows. G. (Website) Livechat --------------------- - [REF] Some `trigger` have been turned into `trigger_up`. - [REF] Some logic has been moved to models (e.g. `{im_livechat.model.WebsiteLivechat}`), from `{im_livechat.im_livechat.LivechatButton}`. - [FIX] New messages should be received in real-time. The longpolling was broken with a recent refactoring on bus service (6448420c5dd160470e465dee7729d19d8d5e7bab).
Diffstat (limited to 'addons/mail/static/src/js/thread_windows/abstract_thread_window.js')
-rw-r--r--addons/mail/static/src/js/thread_windows/abstract_thread_window.js79
1 files changed, 67 insertions, 12 deletions
diff --git a/addons/mail/static/src/js/thread_windows/abstract_thread_window.js b/addons/mail/static/src/js/thread_windows/abstract_thread_window.js
index 8ec8aa84b31..ffed0e16a1f 100644
--- a/addons/mail/static/src/js/thread_windows/abstract_thread_window.js
+++ b/addons/mail/static/src/js/thread_windows/abstract_thread_window.js
@@ -33,10 +33,10 @@ var AbstractThreadWindow = Widget.extend({
events: {
'click .o_thread_window_close': '_onClickClose',
'click .o_thread_window_title': '_onClickFold',
- 'click .o_thread_composer': '_onComposerClick',
+ 'click .o_composer_text_field': '_onComposerClick',
'click .o_mail_thread': '_onThreadWindowClicked',
- 'keydown .o_thread_composer': '_onKeydown',
- 'keypress .o_thread_composer': '_onKeypress',
+ 'keydown .o_composer_text_field': '_onKeydown',
+ 'keypress .o_composer_text_field': '_onKeypress',
},
/**
* Children of this class must make use of `thread`, which is an object that
@@ -50,6 +50,7 @@ var AbstractThreadWindow = Widget.extend({
* thread window is linked to. If not set, it is the "blank" thread
* window.
* @param {Object} [options={}]
+ * @param {mail.model.AbstractThread} [options.thread]
*/
init: function (parent, thread, options) {
this._super(parent);
@@ -65,16 +66,19 @@ var AbstractThreadWindow = Widget.extend({
this._hidden = false;
this._thread = thread || null;
+ this._debouncedOnScroll = _.debounce(this._onScroll.bind(this), 100);
+
if (!this.hasThread()) {
// internal fold state of thread window without any thread
this._folded = false;
}
},
start: function () {
+ var self = this;
this.$input = this.$('.o_composer_text_field');
this.$header = this.$('.o_thread_window_header');
- this.threadWidget = new ThreadWidget(this, {
+ this._threadWidget = new ThreadWidget(this, {
displayDocumentLinks: false,
displayMarkAsRead: false,
displayStars: this.options.displayStars,
@@ -89,7 +93,9 @@ var AbstractThreadWindow = Widget.extend({
var margin_dir = _t.database.parameters.direction === "rtl" ? "margin-left" : "margin-right";
this.$el.css(margin_dir, $.position.scrollbarWidth());
}
- var def = this.threadWidget.replace(this.$('.o_thread_window_content'));
+ var def = this._threadWidget.replace(this.$('.o_thread_window_content')).then(function () {
+ self._threadWidget.$el.on('scroll', self, self._debouncedOnScroll);
+ });
return $.when(this._super(), def);
},
/**
@@ -125,8 +131,9 @@ var AbstractThreadWindow = Widget.extend({
*/
close: function () {},
/**
- * Get the status of the thread, such as the im status of a DM ('online',
- * 'offline', etc.). If this window has no thread, returns `undefined`.
+ * Get the status of the thread, such as the im status of a DM chat
+ * ('online', 'offline', etc.). If this window has no thread, returns
+ * `undefined`.
*
* @returns {string|undefined}
*/
@@ -173,6 +180,15 @@ var AbstractThreadWindow = Widget.extend({
return !! this._thread;
},
/**
+ * Tells whether the bottom of the thread in the thread window is visible
+ * or not.
+ *
+ * @returns {boolean}
+ */
+ isAtBottom: function () {
+ return this._threadWidget.isAtBottom();
+ },
+ /**
* State whether the related thread is folded or not. If there are no
* thread related to this window, it means this is the "blank" thread
* window, therefore we use the internal folded state.
@@ -203,12 +219,21 @@ var AbstractThreadWindow = Widget.extend({
return this._hidden;
},
/**
+ * States whether the input of the thread window should be displayed or not.
+ * By default, any thread window with a thread needs a composer.
+ *
+ * @returns {boolean}
+ */
+ needsComposer: function () {
+ return this.hasThread();
+ },
+ /**
* Render the thread window
*/
render: function () {
this.renderHeader();
if (this.hasThread()) {
- this.threadWidget.render(this._thread, { displayLoadMore: false });
+ this._threadWidget.render(this._thread, { displayLoadMore: false });
}
},
/**
@@ -224,6 +249,12 @@ var AbstractThreadWindow = Widget.extend({
QWeb.render('mail.AbstractThreadWindow.HeaderContent', options));
},
/**
+ * Scroll to the bottom of the thread in the thread window
+ */
+ scrollToBottom: function () {
+ this._threadWidget.scrollToBottom();
+ },
+ /**
* Toggle the fold state of this thread window. Also update the fold state
* of the thread model. If the boolean parameter `folded` is provided, it
* folds/unfolds the window when it is set/unset.
@@ -244,7 +275,7 @@ var AbstractThreadWindow = Widget.extend({
*/
updateVisualFoldState: function () {
if (!this.isFolded()) {
- this.threadWidget.scrollToBottom();
+ this._threadWidget.scrollToBottom();
this._focusInput();
}
this._animateFold();
@@ -311,13 +342,22 @@ var AbstractThreadWindow = Widget.extend({
return this._thread.getID();
},
/**
- * Post a message on this thread window
+ * Post a message on this thread window, and auto-scroll to the bottom of
+ * the thread.
*
- * @abstract
* @private
* @param {Object} messageData
*/
- _postMessage: function (messageData) {},
+ _postMessage: function (messageData) {
+ var self = this;
+ if (!this.hasThread()) {
+ return;
+ }
+ this._thread.postMessage(messageData)
+ .then(function () {
+ self._threadWidget.scrollToBottom();
+ });
+ },
/**
* Update the fold state of the thread.
* This function is called when toggling the fold state of this window.
@@ -334,6 +374,13 @@ var AbstractThreadWindow = Widget.extend({
this._folded = folded;
}
},
+ /**
+ * Warn other mail components that the unread counter has been updated
+ *
+ * @abstract
+ * @private
+ */
+ _warnUpdatedUnreadCounter: function () {},
//--------------------------------------------------------------------------
// Handlers
@@ -417,6 +464,14 @@ var AbstractThreadWindow = Widget.extend({
ev.stopPropagation(); // to prevent jquery's blockUI to cancel event
},
/**
+ * @private
+ */
+ _onScroll: function () {
+ if (this.hasThread() && this.isAtBottom()) {
+ this._thread.markAsRead();
+ }
+ },
+ /**
* When a thread window is clicked on, we want to give the focus to the main
* input. An exception is made when the user is selecting something.
*