[IMP] im_livechat, mail: improved "is typing" notification
With this commit, the UI for "is typing..." notifications
has changed.
** before **:
In Discuss & chat windows, "is typing..." notification bar
at the bottom of the thread, inside the conversation.
** after **
In chat windows, animated '...' next to conversation name.
In Discuss, animated '...' next to conversation name in sidebar,
and text below the composer.
Task-ID 1881001
This commit is contained in:
@@ -360,7 +360,7 @@ var LivechatButton = Widget.extend({
|
||||
*/
|
||||
_onUpdatedTypingPartners: function (ev) {
|
||||
ev.stopPropagation();
|
||||
this._chatWindow.renderTypingNotificationBar();
|
||||
this._chatWindow.renderHeader();
|
||||
},
|
||||
/**
|
||||
* @private
|
||||
|
||||
@@ -123,6 +123,9 @@ var BasicComposer = Widget.extend({
|
||||
$(window).on(this.fileuploadID, this._onAttachmentLoaded.bind(this));
|
||||
this.on('change:attachment_ids', this, this._renderAttachments);
|
||||
|
||||
this.call('mail_service', 'getMailBus')
|
||||
.on('update_typing_partners', this, this._onUpdateTypingPartners);
|
||||
|
||||
// Mention
|
||||
this._mentionManager.prependTo(this.$('.o_composer'));
|
||||
|
||||
@@ -793,6 +796,24 @@ var BasicComposer = Widget.extend({
|
||||
this._mentionManager.detectDelimiter();
|
||||
}
|
||||
},
|
||||
/**
|
||||
* @private
|
||||
* @param {integer|string} threadID
|
||||
*/
|
||||
_onUpdateTypingPartners: function (threadID) {
|
||||
if (!this.options.showTyping) {
|
||||
return;
|
||||
}
|
||||
if (!this.options.thread) {
|
||||
return;
|
||||
}
|
||||
if (this.options.thread.getID() !== threadID) {
|
||||
return;
|
||||
}
|
||||
this.$('.o_composer_thread_typing').html(QWeb.render('mail.Composer.ThreadTyping', {
|
||||
thread: this.options.thread,
|
||||
}));
|
||||
},
|
||||
});
|
||||
|
||||
return BasicComposer;
|
||||
|
||||
@@ -235,12 +235,14 @@ var Discuss = AbstractAction.extend(ControlPanelMixin, {
|
||||
start: function () {
|
||||
var self = this;
|
||||
|
||||
this._basicComposer = new BasicComposer(this,
|
||||
{ mentionPartnersRestricted: true }
|
||||
);
|
||||
this._extendedComposer = new ExtendedComposer(this,
|
||||
{ mentionPartnersRestricted: true }
|
||||
);
|
||||
this._basicComposer = new BasicComposer(this, {
|
||||
mentionPartnersRestricted: true,
|
||||
showTyping: true,
|
||||
});
|
||||
this._extendedComposer = new ExtendedComposer(this, {
|
||||
mentionPartnersRestricted: true,
|
||||
showTyping: true,
|
||||
});
|
||||
this._basicComposer
|
||||
.on('post_message', this, this._onPostMessage)
|
||||
.on('input_focused', this, this._onComposerFocused);
|
||||
@@ -1391,19 +1393,9 @@ var Discuss = AbstractAction.extend(ControlPanelMixin, {
|
||||
},
|
||||
/**
|
||||
* @private
|
||||
* @param {integer|string} threadID
|
||||
*/
|
||||
_onTypingPartnersUpdated: function (threadID) {
|
||||
var self = this;
|
||||
if (this._thread.getID() !== threadID) {
|
||||
return;
|
||||
}
|
||||
if (this._thread.hasTypingNotification()) {
|
||||
// call getMentionpartnerSuggestions in order to correctly fetch members
|
||||
this._thread.getMentionPartnerSuggestions().then(function () {
|
||||
self._threadWidget.renderTypingNotificationBar(self._thread);
|
||||
});
|
||||
}
|
||||
_onTypingPartnersUpdated: function () {
|
||||
this._updateThreads();
|
||||
},
|
||||
/**
|
||||
* @private
|
||||
|
||||
@@ -147,6 +147,15 @@ var ThreadTypingMixin = {
|
||||
hasTypingNotification: function () {
|
||||
return true;
|
||||
},
|
||||
/**
|
||||
* Tells if someone other than current user is typing something on this
|
||||
* thread.
|
||||
*
|
||||
* @returns {boolean}
|
||||
*/
|
||||
isSomeoneTyping: function () {
|
||||
return !(_.isEmpty(this._typingPartnerIDs));
|
||||
},
|
||||
/**
|
||||
* Register someone that is currently typing something in this thread.
|
||||
* If this is the current user that is typing something, don't do anything
|
||||
|
||||
@@ -329,8 +329,7 @@ MailManager.include({
|
||||
.on('is_thread_bottom_visible', this, this._onIsThreadBottomVisible)
|
||||
.on('unsubscribe_from_channel', this, this._onUnsubscribeFromChannel)
|
||||
.on('update_thread_unread_counter', this, this._onUpdateThreadUnreadCounter)
|
||||
.on('update_dm_presence', this, this._onUpdateDmPresence)
|
||||
.on('update_typing_partners', this, this._onTypingPartnersUpdated);
|
||||
.on('update_dm_presence', this, this._onUpdateDmPresence);
|
||||
|
||||
core.bus.on('resize', this, _.debounce(this._repositionThreadWindows.bind(this), 100));
|
||||
},
|
||||
@@ -655,23 +654,6 @@ MailManager.include({
|
||||
_onNewMessage: function (message) {
|
||||
this._updateThreadWindowsFromMessage(message, { keepBottom: true, passively: true });
|
||||
},
|
||||
/**
|
||||
* @private
|
||||
* @param {integer|string} threadID
|
||||
*/
|
||||
_onTypingPartnersUpdated: function (threadID) {
|
||||
var threadWindow = this._getThreadWindow(threadID);
|
||||
if (!threadWindow) {
|
||||
return;
|
||||
}
|
||||
var thread = this.getThread(threadID);
|
||||
if (thread.isChannel()) {
|
||||
// call getMentionpartnerSuggestions in order to correctly fetch members
|
||||
thread.getMentionPartnerSuggestions().then(function () {
|
||||
threadWindow.renderTypingNotificationBar();
|
||||
});
|
||||
}
|
||||
},
|
||||
/**
|
||||
* Close the thread window when unsusbscribe from a channel.
|
||||
*
|
||||
|
||||
@@ -185,12 +185,6 @@ var ThreadWidget = Widget.extend({
|
||||
dateFormat: time.getLangDatetimeFormat(),
|
||||
}));
|
||||
|
||||
// must be after mail.widget.Thread rendering, so that there is the
|
||||
// DOM element for the 'is typing' notification bar
|
||||
if (thread.hasTypingNotification()) {
|
||||
this.renderTypingNotificationBar(thread);
|
||||
}
|
||||
|
||||
_.each(messages, function (message) {
|
||||
var $message = self.$('.o_thread_message[data-message-id="'+ message.getID() +'"]');
|
||||
$message.find('.o_mail_timestamp').data('date', message.getDate());
|
||||
@@ -253,28 +247,6 @@ var ThreadWidget = Widget.extend({
|
||||
});
|
||||
return done;
|
||||
},
|
||||
/**
|
||||
* Render the 'is typing...' text on the typing notification bar of the
|
||||
* thread. This is called when there is a change in the list of users
|
||||
* typing something on this thread.
|
||||
*
|
||||
* @param {mail.model.AbstractThread} thread with ThreadTypingMixin
|
||||
*/
|
||||
renderTypingNotificationBar: function (thread) {
|
||||
if (this._currentThreadID === thread.getID()) {
|
||||
var shouldScrollToBottomAfterRendering = this.isAtBottom();
|
||||
|
||||
// typing notification bar rendering
|
||||
var $typingBar = this.$('.o_thread_typing_notification_bar');
|
||||
var text = thread.getTypingMembersToText();
|
||||
$typingBar.toggleClass('o_hidden', !text); // hide if no text, because of padding
|
||||
$typingBar.text(text);
|
||||
|
||||
if (shouldScrollToBottomAfterRendering) {
|
||||
this.scrollToBottom();
|
||||
}
|
||||
}
|
||||
},
|
||||
/**
|
||||
* Scroll to the bottom of the thread
|
||||
*/
|
||||
|
||||
@@ -138,6 +138,15 @@ var AbstractThreadWindow = Widget.extend({
|
||||
getID: function () {
|
||||
return this._getThreadID();
|
||||
},
|
||||
/**
|
||||
* @returns {mail.model.Thread|undefined}
|
||||
*/
|
||||
getThread: function () {
|
||||
if (!this.hasThread) {
|
||||
return undefined;
|
||||
}
|
||||
return this._thread;
|
||||
},
|
||||
/**
|
||||
* 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
|
||||
@@ -256,14 +265,6 @@ var AbstractThreadWindow = Widget.extend({
|
||||
this.$header.html(
|
||||
QWeb.render('mail.AbstractThreadWindow.HeaderContent', options));
|
||||
},
|
||||
/**
|
||||
* Render the 'is typing...' notification bar text on the thread in this
|
||||
* thread window. This is called when there is a change in the list of users
|
||||
* currently typing something on this thread.
|
||||
*/
|
||||
renderTypingNotificationBar: function () {
|
||||
this._threadWidget.renderTypingNotificationBar(this._thread);
|
||||
},
|
||||
/**
|
||||
* Scroll to the bottom of the thread in the thread window
|
||||
*/
|
||||
@@ -339,6 +340,7 @@ var AbstractThreadWindow = Widget.extend({
|
||||
_getHeaderRenderingOptions: function () {
|
||||
return {
|
||||
status: this.getThreadStatus(),
|
||||
thread: this.getThread(),
|
||||
title: this.getTitle(),
|
||||
unreadCounter: this.getUnreadCounter(),
|
||||
widget: this,
|
||||
|
||||
@@ -55,6 +55,9 @@ var ThreadWindow = AbstractThreadWindow.extend({
|
||||
|
||||
var superDef = this._super().then(this._listenThreadWidget.bind(this));
|
||||
|
||||
this.call('mail_service', 'getMailBus')
|
||||
.on('update_typing_partners', this, this._onUpdateTypingPartners);
|
||||
|
||||
var composerDef;
|
||||
if (!this.hasThread()) {
|
||||
this._startWithoutThread();
|
||||
@@ -353,7 +356,19 @@ var ThreadWindow = AbstractThreadWindow.extend({
|
||||
var message = this.call('mail_service', 'getMessage', messageID);
|
||||
message.toggleStarStatus();
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @param {integer|string} threadID
|
||||
*/
|
||||
_onUpdateTypingPartners: function (threadID) {
|
||||
if (!this.hasThread()) {
|
||||
return;
|
||||
}
|
||||
if (this._thread.getID() !== threadID) {
|
||||
return;
|
||||
}
|
||||
this.renderHeader();
|
||||
},
|
||||
});
|
||||
|
||||
return ThreadWindow;
|
||||
|
||||
@@ -57,6 +57,14 @@ $o-mail-thread-window-zindex: $zindex-modal + 1 !default;
|
||||
cursor: pointer;
|
||||
flex: 1 1 auto;
|
||||
@include o-text-overflow;
|
||||
|
||||
.o_mail_thread_typing_icon {
|
||||
padding-left: 2px;
|
||||
|
||||
.o_mail_thread_typing_icon_dot {
|
||||
background: gray('300');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.o_thread_window_buttons {
|
||||
@@ -76,10 +84,6 @@ $o-mail-thread-window-zindex: $zindex-modal + 1 !default;
|
||||
overflow: auto;
|
||||
-webkit-overflow-scrolling: touch; // smooth scrolling in iOS app (Safari)
|
||||
|
||||
.o_thread_typing_notification_bar {
|
||||
background-color: rgba($o-mail-thread-window-bg, 0.75);
|
||||
}
|
||||
|
||||
.o_thread_date_separator {
|
||||
margin: 0px 0px 15px 0px;
|
||||
.o_thread_date {
|
||||
|
||||
@@ -184,6 +184,11 @@
|
||||
flex: 1 0 100%;
|
||||
}
|
||||
|
||||
.o_composer_thread_typing {
|
||||
font-size: 0.9em;
|
||||
color: gray('600');
|
||||
}
|
||||
|
||||
.o_chatter_composer_tools {
|
||||
border: none;
|
||||
border-left: 1px solid gray('300');
|
||||
|
||||
@@ -44,6 +44,9 @@
|
||||
flex: 1 1 auto;
|
||||
@include o-text-overflow;
|
||||
}
|
||||
.o_mail_thread_typing_icon_dot {
|
||||
background: gray('600');;
|
||||
}
|
||||
.o_mail_sidebar_needaction, .o_mail_partner_unpin, .o_mail_channel_settings {
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
@@ -129,7 +132,7 @@
|
||||
background-color: darken(gray('900'),2%);
|
||||
|
||||
.o_mail_partner_unpin, .o_mail_channel_settings {
|
||||
opacity: $o-mail-sidebar-icon-opacity;
|
||||
display: inline-block;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -143,7 +146,7 @@
|
||||
}
|
||||
|
||||
.o_mail_partner_unpin, .o_mail_channel_settings {
|
||||
@include o-hover-opacity($default-opacity: 0, $hover-opacity: 1);
|
||||
display: none;
|
||||
}
|
||||
&.o_unread_message {
|
||||
color: white;
|
||||
|
||||
@@ -13,26 +13,6 @@
|
||||
height: 15px;
|
||||
}
|
||||
|
||||
.o_thread_typing_notification_free_space {
|
||||
flex-grow: 1,
|
||||
}
|
||||
|
||||
.o_thread_typing_notification_bar {
|
||||
flex: 0, 0, 20px;
|
||||
background-color: rgba($white, 0.75);
|
||||
padding: 5px;
|
||||
text-align: center;
|
||||
color: gray('600');
|
||||
|
||||
&.o_thread_order_asc {
|
||||
@include o-position-sticky($bottom: 0px);
|
||||
}
|
||||
|
||||
&.o_thread_order_desc {
|
||||
@include o-position-sticky($top: 0px);
|
||||
}
|
||||
}
|
||||
|
||||
.o_thread_tooltip_container {
|
||||
display: inline;
|
||||
position: relative;
|
||||
@@ -239,3 +219,40 @@
|
||||
opacity: $o-mail-thread-icon-opacity;
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
// Thread typing icon: shared between discuss and chat windows
|
||||
// ------------------------------------------------------------------
|
||||
|
||||
.o_mail_thread_typing_icon {
|
||||
position: relative;
|
||||
text-align: center;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
|
||||
.o_mail_thread_typing_icon_dot {
|
||||
display: inline-block;
|
||||
width: 3px;
|
||||
height: 3px;
|
||||
border-radius: 50%;
|
||||
background: gray('800');
|
||||
animation: o_mail_thread_typing_icon_dot 1.5s linear infinite;
|
||||
|
||||
&:nth-child(2) {
|
||||
animation-delay: -1.35s;
|
||||
}
|
||||
|
||||
&:nth-child(3) {
|
||||
animation-delay: -1.2s;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes o_mail_thread_typing_icon_dot {
|
||||
0%, 40%, 100% {
|
||||
transform: initial;
|
||||
}
|
||||
20% {
|
||||
transform: translateY(-5px);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
<t t-set="status" t-value="widget.getThreadStatus()"/>
|
||||
<t t-set="title" t-value="widget.getTitle()"/>
|
||||
<t t-set="unreadCounter" t-value="widget.getUnreadCounter()"/>
|
||||
<t t-set="thread" t-value="widget.getThread()"/>
|
||||
</t>
|
||||
</div>
|
||||
<div class="o_thread_window_content">
|
||||
@@ -58,6 +59,7 @@
|
||||
name of the document.
|
||||
@param {integer} [unreadCounter] the number of unread messages on the
|
||||
thread.
|
||||
@param {mail.model.Thread|undefined} thread
|
||||
@param {Object} widget
|
||||
@param {function} widget.isMobile function without any param that
|
||||
states whether it should render for desktop or mobile screen.
|
||||
@@ -70,6 +72,7 @@
|
||||
<t t-if="status" t-call="mail.UserStatus"/>
|
||||
<t t-esc="title"/>
|
||||
<span t-if="unreadCounter"> (<t t-esc="unreadCounter"/>)</span>
|
||||
<t t-if="thread and thread.hasTypingNotification() and thread.isSomeoneTyping()" t-call="mail.ThreadTypingIcon"/>
|
||||
</span>
|
||||
<span t-if="!widget.isMobile()" class="o_thread_window_buttons">
|
||||
<a href="#" class="o_thread_window_close fa fa-close"/>
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="o_composer_attachments_list"/>
|
||||
<div class="o_composer_thread_typing"/>
|
||||
</div>
|
||||
<div class="o_composer_send">
|
||||
<button tabindex="3" class="btn btn-primary o_composer_button_send d-none d-md-inline-block" type="button"><t t-esc="widget.options.sendText"/></button>
|
||||
@@ -40,6 +41,13 @@
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<!--
|
||||
@param {mail.model.Thread} thread
|
||||
-->
|
||||
<t t-name="mail.Composer.ThreadTyping">
|
||||
<t t-esc="thread.getTypingMembersToText()"/>
|
||||
</t>
|
||||
|
||||
<div t-name="mail.Composer.emojis" class="o_mail_emoji_container">
|
||||
<t t-foreach="emojis" t-as="emoji">
|
||||
<button t-att-data-emoji="emoji.sources[0]" class="btn btn-link o_mail_emoji" t-att-title="emoji.description" t-att-aria-label="emoji.description">
|
||||
|
||||
@@ -140,6 +140,10 @@
|
||||
<t t-esc="_.unescape(thread.getName())"/>
|
||||
<i t-if="thread.isMassMailing()" class="fa fa-envelope-o" title="Sends messages by email" role="img" aria-label="Send by mail"/>
|
||||
</span>
|
||||
<t t-if="channel.hasTypingNotification() and channel.isSomeoneTyping()">
|
||||
<t t-set="thread" t-value="channel"/>
|
||||
<t t-call="mail.ThreadTypingIcon"/>
|
||||
</t>
|
||||
<span t-attf-class="fa fa-cog o_mail_channel_settings"
|
||||
title="Channel settings" role="img" aria-label="Channel settings" t-att-data-thread-id="thread.getID()"/>
|
||||
<t t-call="mail.discuss.SidebarCounter"/>
|
||||
|
||||
@@ -191,7 +191,6 @@
|
||||
<t t-if="options.displayBottomThreadFreeSpace">
|
||||
<div class="o_thread_bottom_free_space"/>
|
||||
</t>
|
||||
<t t-if="thread.hasTypingNotification()" t-call="mail.widget.Thread.TypingNotificationBar"/>
|
||||
</div>
|
||||
</t>
|
||||
|
||||
@@ -217,26 +216,11 @@
|
||||
<div class="o_mail_thread_content">
|
||||
<t t-if="options.messagesSeparatorPosition == 'top'" t-call="mail.MessagesSeparator"/>
|
||||
<t t-set="messages" t-value="messages.slice().reverse()"/>
|
||||
<t t-if="thread.hasTypingNotification()" t-call="mail.widget.Thread.TypingNotificationBar"/>
|
||||
<t t-call="mail.widget.Thread.Messages"/>
|
||||
<t t-if="options.displayLoadMore" t-call="mail.widget.Thread.LoadMore"/>
|
||||
</div>
|
||||
</t>
|
||||
|
||||
<!--
|
||||
@param {mail.model.AbstractThread} thread
|
||||
-->
|
||||
<t t-name="mail.widget.Thread.TypingNotificationBar">
|
||||
<t t-if="options.displayOrder === ORDER.ASC">
|
||||
<div class="o_thread_typing_notification_free_space"/>
|
||||
<div class="o_thread_typing_notification_bar o_thread_order_asc"/>
|
||||
</t>
|
||||
<t t-else="">
|
||||
<div class="o_thread_typing_notification_free_space"/>
|
||||
<div class="o_thread_typing_notification_bar o_thread_order_desc"/>
|
||||
</t>
|
||||
</t>
|
||||
|
||||
<!--
|
||||
@param {mail.model.AbstractMessage[]} messages messages are ordered based
|
||||
on desired display order
|
||||
@@ -550,4 +534,16 @@
|
||||
</t>
|
||||
</div>
|
||||
</t>
|
||||
|
||||
<!--
|
||||
@param {mail.model.Thread} thread with typing feature
|
||||
-->
|
||||
<t t-name="mail.ThreadTypingIcon">
|
||||
<span class="o_mail_thread_typing_icon" t-att-title="thread.getTypingMembersToText()">
|
||||
<span class="o_mail_thread_typing_icon_dot"/>
|
||||
<span class="o_mail_thread_typing_icon_dot"/>
|
||||
<span class="o_mail_thread_typing_icon_dot"/>
|
||||
</span>
|
||||
</t>
|
||||
|
||||
</templates>
|
||||
|
||||
@@ -906,6 +906,10 @@ QUnit.test('confirm dialog when administrator leave (not chat) channel', functio
|
||||
})
|
||||
.then(function (discuss) {
|
||||
// Unsubscribe on MyChannel as administrator
|
||||
// The unpin icon is only shown when hovering on sidebar item.
|
||||
// helpter dom.click needs the element to be visible, hence the
|
||||
// hack on display of this icon.
|
||||
discuss.$('.o_mail_partner_unpin').css('display', 'block');
|
||||
testUtils.dom.click(discuss.$('.o_mail_partner_unpin'));
|
||||
|
||||
assert.strictEqual($('.modal-dialog').length, 1,
|
||||
|
||||
@@ -54,7 +54,6 @@ QUnit.module('Discuss (Typing Notifications)', {
|
||||
this.patch();
|
||||
|
||||
// Frequently used data for tests
|
||||
this.generalChannelID = 1;
|
||||
this.myName = "Myself";
|
||||
this.myPartnerID = 30;
|
||||
|
||||
@@ -62,7 +61,7 @@ QUnit.module('Discuss (Typing Notifications)', {
|
||||
initMessaging: {
|
||||
channel_slots: {
|
||||
channel_channel: [{
|
||||
id: this.generalChannelID,
|
||||
id: 1,
|
||||
channel_type: "channel",
|
||||
name: "general",
|
||||
}],
|
||||
@@ -114,10 +113,10 @@ QUnit.module('Discuss (Typing Notifications)', {
|
||||
records: [{
|
||||
author_id: [this.myPartnerID, this.myName],
|
||||
body: "<p>first message</p>",
|
||||
channel_ids: [this.generalChannelID],
|
||||
channel_ids: [1],
|
||||
id: 100,
|
||||
model: 'mail.channel',
|
||||
res_id: this.generalChannelID,
|
||||
res_id: 1,
|
||||
}],
|
||||
},
|
||||
};
|
||||
@@ -158,7 +157,6 @@ QUnit.test('notify is typing', function (assert) {
|
||||
assert.expect(11);
|
||||
var done = assert.async();
|
||||
|
||||
var self = this;
|
||||
// this is to track the step that we are testing in the `notify_typing`
|
||||
// mocked RPC
|
||||
var step = 1;
|
||||
@@ -175,13 +173,13 @@ QUnit.test('notify is typing', function (assert) {
|
||||
var channelID = args.args[0];
|
||||
if (step === 1) {
|
||||
// user notify that he is typing
|
||||
assert.strictEqual(channelID, self.generalChannelID,
|
||||
assert.strictEqual(channelID, 1,
|
||||
"should send a typing notification on general channel");
|
||||
assert.strictEqual(args.kwargs.is_typing, true,
|
||||
"should send a currently typing notification");
|
||||
step++;
|
||||
} else if (step === 2) {
|
||||
assert.strictEqual(channelID, self.generalChannelID,
|
||||
assert.strictEqual(channelID, 1,
|
||||
"should send a typing notification on general channel");
|
||||
assert.strictEqual(args.kwargs.is_typing, false,
|
||||
"should send a stopped typing notification");
|
||||
@@ -224,12 +222,9 @@ QUnit.test('notify is typing', function (assert) {
|
||||
});
|
||||
|
||||
QUnit.test('receive is typing notification', function (assert) {
|
||||
assert.expect(7);
|
||||
var done = assert.async();
|
||||
assert.expect(10);
|
||||
|
||||
var self = this;
|
||||
var fetchListenersDef = $.Deferred();
|
||||
|
||||
createDiscuss({
|
||||
id: 1,
|
||||
context: {},
|
||||
@@ -240,7 +235,6 @@ QUnit.test('receive is typing notification', function (assert) {
|
||||
// when receiving an 'is typing' notification, fetch the list of
|
||||
// members of this channel if we haven't done yet.
|
||||
if (args.method === 'channel_fetch_listeners') {
|
||||
fetchListenersDef.resolve();
|
||||
return $.when([
|
||||
{ id: self.myPartnerID, name: self.myName },
|
||||
{ id: 42, name: "Someone" },
|
||||
@@ -257,49 +251,58 @@ QUnit.test('receive is typing notification', function (assert) {
|
||||
assert.hasAttrValue($general, 'title', 'general',
|
||||
"should have the title 'general'");
|
||||
|
||||
// pick 1st composer (basic), not 2nd composer (extended, hidden)
|
||||
var $composer = discuss.$('.o_thread_composer').first();
|
||||
|
||||
// click on general
|
||||
testUtils.dom.click($general);
|
||||
assert.containsOnce(discuss, '.o_thread_typing_notification_bar',
|
||||
"there should be a typing notification bar on the thread");
|
||||
assert.isNotVisible(discuss.$('.o_thread_typing_notification_bar'),
|
||||
"the typing notification bar should be hidden by default");
|
||||
assert.containsNone($general, '.o_mail_thread_typing_icon',
|
||||
"should no longer show someone is typing in sidebar of discuss");
|
||||
assert.strictEqual($composer.find('.o_composer_thread_typing').text().trim(), "",
|
||||
"should no longer show someone is typing on the composer of active thread");
|
||||
|
||||
self.simulateIsTyping({
|
||||
channelID: self.generalChannelID,
|
||||
channelID: 1,
|
||||
isTyping: true,
|
||||
partnerID: 42,
|
||||
widget: discuss,
|
||||
});
|
||||
|
||||
fetchListenersDef.then(function () {
|
||||
assert.isVisible(discuss.$('.o_thread_typing_notification_bar'),
|
||||
"the typing notification bar should be visible when someone is typing something");
|
||||
assert.strictEqual(discuss.$('.o_thread_typing_notification_bar').text(),
|
||||
"Someone is typing...",
|
||||
"It should display that the other user is typing something");
|
||||
$general = discuss.$('.o_mail_discuss_sidebar')
|
||||
.find('.o_mail_discuss_item[data-thread-id=1]');
|
||||
assert.containsOnce($general, '.o_mail_thread_typing_icon',
|
||||
"should have a thread typing icon next to general icon in the sidebar");
|
||||
assert.hasAttrValue($general.find('.o_mail_thread_typing_icon'), 'title',
|
||||
"Someone is typing...",
|
||||
"should show who is typing on hover on this thread typing icon");
|
||||
assert.containsOnce($composer, '.o_composer_thread_typing',
|
||||
"should show typing info on the composer of active thread");
|
||||
assert.strictEqual($composer.find('.o_composer_thread_typing').text().trim(),
|
||||
"Someone is typing...",
|
||||
"should show who is typing on the composer of active thread");
|
||||
|
||||
self.simulateIsTyping({
|
||||
channelID: self.generalChannelID,
|
||||
isTyping: false,
|
||||
partnerID: 42,
|
||||
widget: discuss,
|
||||
});
|
||||
assert.isNotVisible(discuss.$('.o_thread_typing_notification_bar'),
|
||||
"the typing notification bar should be hidden when someone stops typing something");
|
||||
|
||||
discuss.destroy();
|
||||
done();
|
||||
self.simulateIsTyping({
|
||||
channelID: 1,
|
||||
isTyping: false,
|
||||
partnerID: 42,
|
||||
widget: discuss,
|
||||
});
|
||||
|
||||
$general = discuss.$('.o_mail_discuss_sidebar')
|
||||
.find('.o_mail_discuss_item[data-thread-id=1]');
|
||||
assert.containsNone($general, '.o_mail_thread_typing_icon',
|
||||
"should no longer show someone is typing in sidebar of discuss");
|
||||
assert.strictEqual($composer.find('.o_composer_thread_typing').text().trim(), "",
|
||||
"should no longer show someone is typing on the composer of active thread");
|
||||
|
||||
discuss.destroy();
|
||||
});
|
||||
});
|
||||
|
||||
QUnit.test('receive message of someone that was typing something', function (assert) {
|
||||
assert.expect(4);
|
||||
var done = assert.async();
|
||||
assert.expect(6);
|
||||
|
||||
var self = this;
|
||||
var fetchListenersDef = $.Deferred();
|
||||
|
||||
createDiscuss({
|
||||
id: 1,
|
||||
context: {},
|
||||
@@ -310,7 +313,6 @@ QUnit.test('receive message of someone that was typing something', function (ass
|
||||
// when receiving an 'is typing' notification, fetch the list of
|
||||
// members of this channel if we haven't done yet.
|
||||
if (args.method === 'channel_fetch_listeners') {
|
||||
fetchListenersDef.resolve();
|
||||
return $.when([
|
||||
{ id: self.myPartnerID, name: self.myName },
|
||||
{ id: 42, name: "Someone" },
|
||||
@@ -324,51 +326,56 @@ QUnit.test('receive message of someone that was typing something', function (ass
|
||||
var $general = discuss.$('.o_mail_discuss_sidebar .o_mail_discuss_item[data-thread-id=1]');
|
||||
testUtils.dom.click($general);
|
||||
|
||||
assert.isNotVisible(discuss.$('.o_thread_typing_notification_bar'),
|
||||
"the typing notification bar should be hidden by default");
|
||||
// pick 1st composer (basic), not 2nd composer (extended, hidden)
|
||||
var $composer = discuss.$('.o_thread_composer').first();
|
||||
|
||||
self.simulateIsTyping({
|
||||
channelID: self.generalChannelID,
|
||||
channelID: 1,
|
||||
isTyping: true,
|
||||
partnerID: 42,
|
||||
widget: discuss,
|
||||
});
|
||||
|
||||
fetchListenersDef.then(function () {
|
||||
assert.isVisible(discuss.$('.o_thread_typing_notification_bar'),
|
||||
"the typing notification bar should be visible when someone is typing something");
|
||||
assert.strictEqual(discuss.$('.o_thread_typing_notification_bar').text(),
|
||||
"Someone is typing...",
|
||||
"It should display that the other user is typing something");
|
||||
$general = discuss.$('.o_mail_discuss_sidebar')
|
||||
.find('.o_mail_discuss_item[data-thread-id=1]');
|
||||
assert.containsOnce($general, '.o_mail_thread_typing_icon',
|
||||
"should have a thread typing icon next to general icon in the sidebar");
|
||||
assert.hasAttrValue($general.find('.o_mail_thread_typing_icon'), 'title',
|
||||
"Someone is typing...",
|
||||
"should show who is typing on hover on this thread typing icon");
|
||||
assert.containsOnce($composer, '.o_composer_thread_typing',
|
||||
"should show typing info on the composer of active thread");
|
||||
assert.strictEqual($composer.find('.o_composer_thread_typing').text().trim(),
|
||||
"Someone is typing...",
|
||||
"should show who is typing on the composer of active thread");
|
||||
|
||||
// Simulate receive message from the person typing something
|
||||
var messageData = {
|
||||
author_id: [42, 'Someone'],
|
||||
body: "<p>test</p>",
|
||||
channel_ids: [self.generalChannelID],
|
||||
id: 101,
|
||||
model: 'mail.channel',
|
||||
res_id: self.generalChannelID,
|
||||
};
|
||||
var notification = [[false, 'mail.channel', self.generalChannelID], messageData];
|
||||
discuss.call('bus_service', 'trigger', 'notification', [notification]);
|
||||
// Simulate receive message from the person typing something
|
||||
var messageData = {
|
||||
author_id: [42, 'Someone'],
|
||||
body: "<p>test</p>",
|
||||
channel_ids: [1],
|
||||
id: 101,
|
||||
model: 'mail.channel',
|
||||
res_id: 1,
|
||||
};
|
||||
var notification = [[false, 'mail.channel', 1], messageData];
|
||||
discuss.call('bus_service', 'trigger', 'notification', [notification]);
|
||||
|
||||
assert.isNotVisible(discuss.$('.o_thread_typing_notification_bar'),
|
||||
"the typing notification bar should be hidden when receiving message from someone that was typing some text");
|
||||
$general = discuss.$('.o_mail_discuss_sidebar')
|
||||
.find('.o_mail_discuss_item[data-thread-id=1]');
|
||||
assert.containsNone($general, '.o_mail_thread_typing_icon',
|
||||
"should no longer show someone is typing in sidebar of discuss, after receiving message");
|
||||
assert.strictEqual($composer.find('.o_composer_thread_typing').text().trim(), "",
|
||||
"should no longer show someone is typing on the composer of active thread, after receiving message");
|
||||
|
||||
discuss.destroy();
|
||||
done();
|
||||
});
|
||||
discuss.destroy();
|
||||
});
|
||||
});
|
||||
|
||||
QUnit.test('do not display myself as typing', function (assert) {
|
||||
assert.expect(3);
|
||||
var done = assert.async();
|
||||
assert.expect(2);
|
||||
|
||||
var self = this;
|
||||
var fetchListenersDef = $.Deferred();
|
||||
|
||||
createDiscuss({
|
||||
id: 1,
|
||||
context: {},
|
||||
@@ -379,7 +386,6 @@ QUnit.test('do not display myself as typing', function (assert) {
|
||||
// when receiving an 'is typing' notification, fetch the list of
|
||||
// members of this channel if we haven't done yet.
|
||||
if (args.method === 'channel_fetch_listeners') {
|
||||
fetchListenersDef.resolve();
|
||||
return $.when([
|
||||
{ id: self.myPartnerID, name: self.myName },
|
||||
]);
|
||||
@@ -388,29 +394,28 @@ QUnit.test('do not display myself as typing', function (assert) {
|
||||
},
|
||||
session: { partner_id: this.myPartnerID },
|
||||
}).then(function (discuss) {
|
||||
// click on general
|
||||
// click on general channel
|
||||
var $general = discuss.$('.o_mail_discuss_sidebar')
|
||||
.find('.o_mail_discuss_item[data-thread-id=1]');
|
||||
testUtils.dom.click($general);
|
||||
assert.containsOnce(discuss, '.o_thread_typing_notification_bar',
|
||||
"there should be a typing notification bar on the thread");
|
||||
assert.isNotVisible(discuss.$('.o_thread_typing_notification_bar'),
|
||||
"the typing notification bar should be hidden by default");
|
||||
// pick 1st composer (basic), not 2nd composer (extended, hidden)
|
||||
var $composer = discuss.$('.o_thread_composer').first();
|
||||
|
||||
self.simulateIsTyping({
|
||||
channelID: self.generalChannelID,
|
||||
channelID: 1,
|
||||
isTyping: true,
|
||||
partnerID: self.myPartnerID,
|
||||
widget: discuss,
|
||||
});
|
||||
|
||||
fetchListenersDef.then(function () {
|
||||
assert.isNotVisible(discuss.$('.o_thread_typing_notification_bar'),
|
||||
"the typing notification bar should still be hidden when I am typing something");
|
||||
$general = discuss.$('.o_mail_discuss_sidebar')
|
||||
.find('.o_mail_discuss_item[data-thread-id=1]');
|
||||
assert.containsNone($general, '.o_mail_thread_typing_icon',
|
||||
"should not show current user is typing in sidebar of discuss");
|
||||
assert.strictEqual($composer.find('.o_composer_thread_typing').text().trim(), "",
|
||||
"should not show current user is typing on the composer of active thread");
|
||||
|
||||
discuss.destroy();
|
||||
done();
|
||||
});
|
||||
discuss.destroy();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -420,12 +425,9 @@ QUnit.test('several users typing something at the same time', function (assert)
|
||||
// have been typing something for the longest time.
|
||||
// @see mail.model.ThreadTypingMixin:getTypingMembersToText for the rule
|
||||
// applied for displaying the typing notification text.
|
||||
assert.expect(9);
|
||||
var done = assert.async();
|
||||
assert.expect(10);
|
||||
|
||||
var self = this;
|
||||
var fetchListenersDef = $.Deferred();
|
||||
|
||||
createDiscuss({
|
||||
id: 1,
|
||||
context: {},
|
||||
@@ -436,7 +438,6 @@ QUnit.test('several users typing something at the same time', function (assert)
|
||||
// when receiving an 'is typing' notification, fetch the list of
|
||||
// members of this channel if we haven't done yet.
|
||||
if (args.method === 'channel_fetch_listeners') {
|
||||
fetchListenersDef.resolve();
|
||||
return $.when([
|
||||
{ id: self.myPartnerID, name: self.myName },
|
||||
{ id: 42, name: "Someone" },
|
||||
@@ -448,70 +449,85 @@ QUnit.test('several users typing something at the same time', function (assert)
|
||||
},
|
||||
session: { partner_id: this.myPartnerID },
|
||||
}).then(function (discuss) {
|
||||
|
||||
// click on general channel
|
||||
var $general = discuss.$('.o_mail_discuss_sidebar')
|
||||
.find('.o_mail_discuss_item[data-thread-id=1]');
|
||||
assert.strictEqual($general.length, 1,
|
||||
"should have the channel item with id 1");
|
||||
assert.hasAttrValue($general, 'title', 'general',
|
||||
"should have the title 'general'");
|
||||
|
||||
// click on general
|
||||
testUtils.dom.click($general);
|
||||
assert.containsOnce(discuss, '.o_thread_typing_notification_bar',
|
||||
"there should be a typing notification bar on the thread");
|
||||
assert.isNotVisible(discuss.$('.o_thread_typing_notification_bar'),
|
||||
"the typing notification bar should be hidden by default");
|
||||
|
||||
// pick 1st composer (basic), not 2nd composer (extended, hidden)
|
||||
var $composer = discuss.$('.o_thread_composer').first();
|
||||
|
||||
self.simulateIsTyping({
|
||||
channelID: self.generalChannelID,
|
||||
channelID: 1,
|
||||
isTyping: true,
|
||||
partnerID: 42,
|
||||
widget: discuss,
|
||||
});
|
||||
|
||||
fetchListenersDef.then(function () {
|
||||
assert.isVisible(discuss.$('.o_thread_typing_notification_bar'),
|
||||
"the typing notification bar should be visible when someone is typing something");
|
||||
assert.strictEqual(discuss.$('.o_thread_typing_notification_bar').text(),
|
||||
"Someone is typing...",
|
||||
"It should display that the other user is typing something");
|
||||
$general = discuss.$('.o_mail_discuss_sidebar')
|
||||
.find('.o_mail_discuss_item[data-thread-id=1]');
|
||||
assert.containsOnce($general, '.o_mail_thread_typing_icon',
|
||||
"should have a thread typing icon next to general icon in the sidebar");
|
||||
assert.hasAttrValue($general.find('.o_mail_thread_typing_icon'), 'title',
|
||||
"Someone is typing...",
|
||||
"should show someone is typing on hover on this thread typing icon");
|
||||
assert.containsOnce($composer, '.o_composer_thread_typing',
|
||||
"should show typing info on the composer of active thread");
|
||||
assert.strictEqual($composer.find('.o_composer_thread_typing').text().trim(),
|
||||
"Someone is typing...",
|
||||
"should show someone is typing on the composer of active thread");
|
||||
|
||||
self.simulateIsTyping({
|
||||
channelID: self.generalChannelID,
|
||||
isTyping: true,
|
||||
partnerID: 43,
|
||||
widget: discuss,
|
||||
});
|
||||
assert.strictEqual(discuss.$('.o_thread_typing_notification_bar').text(),
|
||||
"Someone and Anonymous are typing...",
|
||||
"It should display the two users that are typing something");
|
||||
|
||||
self.simulateIsTyping({
|
||||
channelID: self.generalChannelID,
|
||||
isTyping: true,
|
||||
partnerID: 44,
|
||||
widget: discuss,
|
||||
});
|
||||
assert.strictEqual(discuss.$('.o_thread_typing_notification_bar').text(),
|
||||
"Someone, Anonymous and more are typing...",
|
||||
"It should display that several users are typing something");
|
||||
|
||||
self.simulateIsTyping({
|
||||
channelID: self.generalChannelID,
|
||||
isTyping: false,
|
||||
partnerID: 42,
|
||||
widget: discuss,
|
||||
});
|
||||
|
||||
assert.strictEqual(discuss.$('.o_thread_typing_notification_bar').text(),
|
||||
"Anonymous and Shy Guy are typing...",
|
||||
"It should omit Someone that is typing");
|
||||
|
||||
discuss.destroy();
|
||||
done();
|
||||
self.simulateIsTyping({
|
||||
channelID: 1,
|
||||
isTyping: true,
|
||||
partnerID: 43,
|
||||
widget: discuss,
|
||||
});
|
||||
|
||||
$general = discuss.$('.o_mail_discuss_sidebar')
|
||||
.find('.o_mail_discuss_item[data-thread-id=1]');
|
||||
assert.hasAttrValue($general.find('.o_mail_thread_typing_icon'), 'title',
|
||||
"Someone and Anonymous are typing...",
|
||||
"should show someone and anonymous are simultaneously typing on hover on this thread typing icon");
|
||||
assert.strictEqual($composer.find('.o_composer_thread_typing').text().trim(),
|
||||
"Someone and Anonymous are typing...",
|
||||
"should show someone and anonymous are simultaneously typing on the composer of active thread");
|
||||
|
||||
self.simulateIsTyping({
|
||||
channelID: 1,
|
||||
isTyping: true,
|
||||
partnerID: 44,
|
||||
widget: discuss,
|
||||
});
|
||||
|
||||
$general = discuss.$('.o_mail_discuss_sidebar')
|
||||
.find('.o_mail_discuss_item[data-thread-id=1]');
|
||||
assert.hasAttrValue($general.find('.o_mail_thread_typing_icon'), 'title',
|
||||
"Someone, Anonymous and more are typing...",
|
||||
"should show 2 and more users are simultaneously typing on hover on this thread typing icon");
|
||||
assert.strictEqual($composer.find('.o_composer_thread_typing').text().trim(),
|
||||
"Someone, Anonymous and more are typing...",
|
||||
"should show 2 and more users are simultaneously typing on the composer of active thread");
|
||||
|
||||
self.simulateIsTyping({
|
||||
channelID: 1,
|
||||
isTyping: false,
|
||||
partnerID: 42,
|
||||
widget: discuss,
|
||||
});
|
||||
|
||||
$general = discuss.$('.o_mail_discuss_sidebar')
|
||||
.find('.o_mail_discuss_item[data-thread-id=1]');
|
||||
assert.hasAttrValue($general.find('.o_mail_thread_typing_icon'), 'title',
|
||||
"Anonymous and Shy Guy are typing...",
|
||||
"should no longer show than someone is typing on hover on this thread typing icon");
|
||||
assert.strictEqual($composer.find('.o_composer_thread_typing').text().trim(),
|
||||
"Anonymous and Shy Guy are typing...",
|
||||
"should no longer show than someone is typing on the composer of active thread");
|
||||
|
||||
discuss.destroy();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -520,12 +536,9 @@ QUnit.test('long typing partner A and in-between short typing partner B', functi
|
||||
// Let's suppose that A is typing a very long message. If B types a short
|
||||
// and sends it, it should display that B is typing, remove B from display
|
||||
// when receiving the message, but still keep A in the typing notification.
|
||||
assert.expect(4);
|
||||
var done = assert.async();
|
||||
assert.expect(8);
|
||||
|
||||
var self = this;
|
||||
var fetchListenersDef = $.Deferred();
|
||||
|
||||
createDiscuss({
|
||||
id: 1,
|
||||
context: {},
|
||||
@@ -536,7 +549,6 @@ QUnit.test('long typing partner A and in-between short typing partner B', functi
|
||||
// when receiving an 'is typing' notification, fetch the list of
|
||||
// members of this channel if we haven't done yet.
|
||||
if (args.method === 'channel_fetch_listeners') {
|
||||
fetchListenersDef.resolve();
|
||||
return $.when([
|
||||
{ id: self.myPartnerID, name: self.myName },
|
||||
{ id: 42, name: "A" },
|
||||
@@ -550,52 +562,136 @@ QUnit.test('long typing partner A and in-between short typing partner B', functi
|
||||
// click on general channel
|
||||
var $general = discuss.$('.o_mail_discuss_sidebar .o_mail_discuss_item[data-thread-id=1]');
|
||||
testUtils.dom.click($general);
|
||||
// pick 1st composer (basic), not 2nd composer (extended, hidden)
|
||||
var $composer = discuss.$('.o_thread_composer').first();
|
||||
|
||||
self.simulateIsTyping({
|
||||
channelID: self.generalChannelID,
|
||||
channelID: 1,
|
||||
isTyping: true,
|
||||
partnerID: 42,
|
||||
widget: discuss,
|
||||
});
|
||||
|
||||
fetchListenersDef.then(function () {
|
||||
assert.isVisible(discuss.$('.o_thread_typing_notification_bar'),
|
||||
"the typing notification bar should be visible when someone is typing something");
|
||||
assert.strictEqual(discuss.$('.o_thread_typing_notification_bar').text(),
|
||||
"A is typing...",
|
||||
"It should display that A is typing something");
|
||||
$general = discuss.$('.o_mail_discuss_sidebar')
|
||||
.find('.o_mail_discuss_item[data-thread-id=1]');
|
||||
assert.containsOnce($general, '.o_mail_thread_typing_icon',
|
||||
"should have a thread typing icon next to general icon in the sidebar");
|
||||
assert.hasAttrValue($general.find('.o_mail_thread_typing_icon'), 'title',
|
||||
"A is typing...",
|
||||
"should show A is typing on hover on this thread typing icon");
|
||||
assert.containsOnce($composer, '.o_composer_thread_typing',
|
||||
"should show typing info on the composer of active thread");
|
||||
assert.strictEqual($composer.find('.o_composer_thread_typing').text().trim(),
|
||||
"A is typing...",
|
||||
"should show A is typing on the composer of active thread");
|
||||
|
||||
self.simulateIsTyping({
|
||||
channelID: self.generalChannelID,
|
||||
isTyping: true,
|
||||
partnerID: 43,
|
||||
widget: discuss,
|
||||
});
|
||||
|
||||
// B comes after A in the display, because A is oldest typing partner.
|
||||
assert.strictEqual(discuss.$('.o_thread_typing_notification_bar').text(),
|
||||
"A and B are typing...",
|
||||
"It should display that A and B are typing something");
|
||||
|
||||
// Simulate receive message from B
|
||||
var messageData = {
|
||||
author_id: [43, 'Someone'],
|
||||
body: "<p>test</p>",
|
||||
channel_ids: [self.generalChannelID],
|
||||
id: 101,
|
||||
model: 'mail.channel',
|
||||
res_id: self.generalChannelID,
|
||||
};
|
||||
var notification = [[false, 'mail.channel', self.generalChannelID], messageData];
|
||||
discuss.call('bus_service', 'trigger', 'notification', [notification]);
|
||||
|
||||
assert.strictEqual(discuss.$('.o_thread_typing_notification_bar').text(),
|
||||
"A is typing...",
|
||||
"It should display that A is still typing something");
|
||||
|
||||
discuss.destroy();
|
||||
done();
|
||||
self.simulateIsTyping({
|
||||
channelID: 1,
|
||||
isTyping: true,
|
||||
partnerID: 43,
|
||||
widget: discuss,
|
||||
});
|
||||
|
||||
// B comes after A in the display, because A is oldest typing partner.
|
||||
$general = discuss.$('.o_mail_discuss_sidebar')
|
||||
.find('.o_mail_discuss_item[data-thread-id=1]');
|
||||
assert.hasAttrValue($general.find('.o_mail_thread_typing_icon'), 'title',
|
||||
"A and B are typing...",
|
||||
"should show A and B are typing on hover on this thread typing icon");
|
||||
assert.strictEqual($composer.find('.o_composer_thread_typing').text().trim(),
|
||||
"A and B are typing...",
|
||||
"should show A and B are typing on the composer of active thread");
|
||||
|
||||
// Simulate receive message from B
|
||||
var messageData = {
|
||||
author_id: [43, 'Someone'],
|
||||
body: "<p>test</p>",
|
||||
channel_ids: [1],
|
||||
id: 101,
|
||||
model: 'mail.channel',
|
||||
res_id: 1,
|
||||
};
|
||||
var notification = [[false, 'mail.channel', 1], messageData];
|
||||
discuss.call('bus_service', 'trigger', 'notification', [notification]);
|
||||
|
||||
$general = discuss.$('.o_mail_discuss_sidebar')
|
||||
.find('.o_mail_discuss_item[data-thread-id=1]');
|
||||
assert.hasAttrValue($general.find('.o_mail_thread_typing_icon'), 'title',
|
||||
"A is typing...",
|
||||
"should show A is still typing on hover on this thread typing icon");
|
||||
assert.strictEqual($composer.find('.o_composer_thread_typing').text().trim(),
|
||||
"A is typing...",
|
||||
"should show A is still typing on the composer of active thread");
|
||||
|
||||
discuss.destroy();
|
||||
});
|
||||
});
|
||||
|
||||
QUnit.test('receive is typing notification from unselected thread', function (assert) {
|
||||
assert.expect(7);
|
||||
|
||||
this.data.initMessaging.channel_slots.channel_channel.push({
|
||||
id: 2,
|
||||
channel_type: "channel",
|
||||
name: "other",
|
||||
});
|
||||
|
||||
var self = this;
|
||||
createDiscuss({
|
||||
id: 1,
|
||||
context: {},
|
||||
params: {},
|
||||
data: this.data,
|
||||
services: this.services,
|
||||
mockRPC: function (route, args) {
|
||||
// when receiving an 'is typing' notification, fetch the list of
|
||||
// members of this channel if we haven't done yet.
|
||||
if (args.method === 'channel_fetch_listeners') {
|
||||
return $.when([
|
||||
{ id: self.myPartnerID, name: self.myName },
|
||||
{ id: 42, name: "Someone" },
|
||||
]);
|
||||
}
|
||||
return this._super.apply(this, arguments);
|
||||
},
|
||||
session: { partner_id: this.myPartnerID },
|
||||
}).then(function (discuss) {
|
||||
var $general = discuss.$('.o_mail_discuss_sidebar')
|
||||
.find('.o_mail_discuss_item[data-thread-id=1]');
|
||||
var $other = discuss.$('.o_mail_discuss_sidebar')
|
||||
.find('.o_mail_discuss_item[data-thread-id=2]');
|
||||
assert.strictEqual($general.length, 1,
|
||||
"should have the channel item with id 1");
|
||||
assert.hasAttrValue($general, 'title', 'general',
|
||||
"should have the title 'general'");
|
||||
assert.strictEqual($other.length, 1,
|
||||
"should have the channel item with id 2");
|
||||
assert.hasAttrValue($other, 'title', 'other',
|
||||
"should have the title 'other'");
|
||||
|
||||
// click on general
|
||||
testUtils.dom.click($general);
|
||||
|
||||
assert.containsNone($general, '.o_mail_thread_typing_icon',
|
||||
"should no longer show someone is typing in sidebar of discuss");
|
||||
|
||||
self.simulateIsTyping({
|
||||
channelID: 2,
|
||||
isTyping: true,
|
||||
partnerID: 42,
|
||||
widget: discuss,
|
||||
});
|
||||
|
||||
$general = discuss.$('.o_mail_discuss_sidebar')
|
||||
.find('.o_mail_discuss_item[data-thread-id=1]');
|
||||
$other = discuss.$('.o_mail_discuss_sidebar')
|
||||
.find('.o_mail_discuss_item[data-thread-id=2]');
|
||||
assert.containsNone($general, '.o_mail_thread_typing_icon',
|
||||
"should not have a thread typing icon next to general icon in the sidebar");
|
||||
assert.containsOnce($other, '.o_mail_thread_typing_icon',
|
||||
"should have a thread typing icon next to other icon in the sidebar");
|
||||
|
||||
discuss.destroy();
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -0,0 +1,128 @@
|
||||
odoo.define('mail.typingThreadWindowTests', function (require) {
|
||||
"use strict";
|
||||
|
||||
var mailTestUtils = require('mail.testUtils');
|
||||
|
||||
var testUtils = require('web.test_utils');
|
||||
var Widget = require('web.Widget');
|
||||
|
||||
QUnit.module('mail', {}, function () {
|
||||
QUnit.module('Thread Window', {}, function () {
|
||||
QUnit.module('Typing', {
|
||||
beforeEach: function () {
|
||||
var self = this;
|
||||
|
||||
// define channel to link to chat window
|
||||
this.data = {
|
||||
'mail.message': {
|
||||
fields: {},
|
||||
records: [],
|
||||
},
|
||||
initMessaging: {
|
||||
channel_slots: {
|
||||
channel_channel: [{
|
||||
id: 1,
|
||||
channel_type: "channel",
|
||||
name: "general",
|
||||
}],
|
||||
},
|
||||
},
|
||||
};
|
||||
this.services = mailTestUtils.getMailServices();
|
||||
this.ORIGINAL_THREAD_WINDOW_APPENDTO = this.services.mail_service.prototype.THREAD_WINDOW_APPENDTO;
|
||||
|
||||
/**
|
||||
* Simulate that someone typing something (or stops typing)
|
||||
*
|
||||
* @param {Object} params
|
||||
* @param {integer} params.channelID
|
||||
* @param {boolean} params.isTyping
|
||||
* @param {integer} params.partnerID
|
||||
* @param {Widget} params.widget a widget that can call the bus_service
|
||||
*/
|
||||
this.simulateIsTyping = function (params) {
|
||||
var typingData = {
|
||||
info: 'typing_status',
|
||||
partner_id: params.partnerID,
|
||||
is_typing: params.isTyping,
|
||||
};
|
||||
var notification = [[false, 'mail.channel', params.channelID], typingData];
|
||||
params.widget.call('bus_service', 'trigger', 'notification', [notification]);
|
||||
};
|
||||
|
||||
this.createParent = function (params) {
|
||||
var widget = new Widget();
|
||||
|
||||
// in non-debug mode, append thread windows in qunit-fixture
|
||||
// note that it does not hide thread window because it uses fixed
|
||||
// position, and qunit-fixture uses absolute...
|
||||
if (params.debug) {
|
||||
self.services.mail_service.prototype.THREAD_WINDOW_APPENDTO = 'body';
|
||||
} else {
|
||||
self.services.mail_service.prototype.THREAD_WINDOW_APPENDTO = '#qunit-fixture';
|
||||
}
|
||||
|
||||
testUtils.mock.addMockEnvironment(widget, params);
|
||||
return widget;
|
||||
};
|
||||
},
|
||||
afterEach: function () {
|
||||
// reset thread window append to body
|
||||
this.services.mail_service.prototype.THREAD_WINDOW_APPENDTO = 'body';
|
||||
},
|
||||
});
|
||||
|
||||
QUnit.test('receive typing notification', function (assert) {
|
||||
assert.expect(4);
|
||||
|
||||
var parent = this.createParent({
|
||||
data: this.data,
|
||||
services: this.services,
|
||||
mockRPC: function (route, args) {
|
||||
// when receiving an 'is typing' notification, fetch the list of
|
||||
// members of this channel if we haven't done yet.
|
||||
if (args.method === 'channel_fetch_listeners') {
|
||||
return $.when([
|
||||
{ id: 42, name: "Someone" },
|
||||
]);
|
||||
}
|
||||
return this._super.apply(this, arguments);
|
||||
},
|
||||
});
|
||||
|
||||
// detach channel 1, so that it opens corresponding thread window.
|
||||
parent.call('mail_service', 'getChannel', 1).detach();
|
||||
|
||||
var $threadWindow = $('.o_thread_window');
|
||||
assert.containsNone($threadWindow, '.o_mail_thread_typing_icon',
|
||||
"should not display an icon that someone is typing something on this thread");
|
||||
|
||||
this.simulateIsTyping({
|
||||
channelID: 1,
|
||||
isTyping: true,
|
||||
partnerID: 42,
|
||||
widget: parent,
|
||||
});
|
||||
|
||||
assert.containsOnce($threadWindow, '.o_mail_thread_typing_icon',
|
||||
"should display an icon that someone is typing something on this thread");
|
||||
assert.hasAttrValue($threadWindow.find('.o_mail_thread_typing_icon'), 'title',
|
||||
"Someone is typing...",
|
||||
"should display someone is typing something on hover of this icon");
|
||||
|
||||
this.simulateIsTyping({
|
||||
channelID: 1,
|
||||
isTyping: false,
|
||||
partnerID: 42,
|
||||
widget: parent,
|
||||
});
|
||||
|
||||
assert.containsNone($threadWindow, '.o_mail_thread_typing_icon',
|
||||
"should no longer display an icon that someone is typing something on this thread");
|
||||
|
||||
parent.destroy();
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -110,6 +110,7 @@
|
||||
<script type="text/javascript" src="/mail/static/tests/thread_window/blank_thread_window_tests.js"></script>
|
||||
<script type="text/javascript" src="/mail/static/tests/thread_window/hidden_thread_window_tests.js"></script>
|
||||
<script type="text/javascript" src="/mail/static/tests/thread_window/moderation_thread_window_tests.js"></script>
|
||||
<script type="text/javascript" src="/mail/static/tests/thread_window/typing_thread_window_tests.js"></script>
|
||||
<script type="text/javascript" src="/mail/static/tests/document_thread_window_tests.js"></script>
|
||||
<script type="text/javascript" src="/mail/static/tests/chatter_tests.js"></script>
|
||||
<script type="text/javascript" src="/mail/static/tests/mail_utils_tests.js"></script>
|
||||
|
||||
Reference in New Issue
Block a user