Commit 2849adf8 authored by JC Brand's avatar JC Brand

Stop debouncing `show`

Instead optimize in other ways.

Also:
- Don't fade in when `animate` is false.
- `trimChats` now gets called in `afterShown`.
- Add now event `beforeShowingChatView`
parent 3a2bf766
......@@ -939,9 +939,10 @@
null, ['rosterGroupsFetched', 'chatBoxesFetched'], {},
async function (done, _converse) {
const sent_stanzas = _converse.connection.sent_stanzas;
// Make the timeouts shorter so that we can test
_converse.TIMEOUTS.PAUSED = 200;
_converse.TIMEOUTS.INACTIVE = 200;
_converse.TIMEOUTS.PAUSED = 100;
_converse.TIMEOUTS.INACTIVE = 100;
await test_utils.waitForRoster(_converse, 'current');
const contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
......@@ -949,38 +950,50 @@
await u.waitUntil(() => _converse.rosterview.el.querySelectorAll('.roster-group').length, 1000);
await test_utils.openChatBoxFor(_converse, contact_jid);
const view = _converse.chatboxviews.get(contact_jid);
await u.waitUntil(() => view.model.get('chat_state') === 'active', 1000);
console.log('chat_state set to active');
await u.waitUntil(() => view.model.get('chat_state') === 'active');
let messages = await u.waitUntil(() => sent_stanzas.filter(s => s.matches('message')));
expect(messages.length).toBe(1);
expect(view.model.get('chat_state')).toBe('active');
view.onKeyDown({
target: view.el.querySelector('textarea.chat-textarea'),
keyCode: 1
});
await u.waitUntil(() => view.model.get('chat_state') === 'composing', 500);
console.log('chat_state set to composing');
expect(view.model.get('chat_state')).toBe('composing');
spyOn(_converse.connection, 'send');
await u.waitUntil(() => view.model.get('chat_state') === 'paused', 1000);
await u.waitUntil(() => view.model.get('chat_state') === 'inactive', 1000);
console.log('chat_state set to inactive');
expect(_converse.connection.send).toHaveBeenCalled();
var calls = _.filter(_converse.connection.send.calls.all(), function (call) {
return call.args[0] instanceof Strophe.Builder;
});
expect(calls.length).toBe(2);
var stanza = calls[0].args[0].tree();
expect(stanza.getAttribute('to')).toBe(contact_jid);
expect(stanza.children.length).toBe(3);
expect(stanza.children[0].tagName).toBe('paused');
expect(stanza.children[1].tagName).toBe('no-store');
expect(stanza.children[2].tagName).toBe('no-permanent-store');
stanza = _converse.connection.send.calls.mostRecent().args[0].tree();
expect(stanza.getAttribute('to')).toBe(contact_jid);
expect(stanza.children.length).toBe(3);
expect(stanza.children[0].tagName).toBe('inactive');
expect(stanza.children[1].tagName).toBe('no-store');
expect(stanza.children[2].tagName).toBe('no-permanent-store');
await u.waitUntil(() => view.model.get('chat_state') === 'composing', 600);
messages = sent_stanzas.filter(s => s.matches('message'));
expect(messages.length).toBe(2);
await u.waitUntil(() => view.model.get('chat_state') === 'paused', 600);
messages = sent_stanzas.filter(s => s.matches('message'));
expect(messages.length).toBe(3);
await u.waitUntil(() => view.model.get('chat_state') === 'inactive', 600);
messages = sent_stanzas.filter(s => s.matches('message'));
expect(messages.length).toBe(4);
expect(Strophe.serialize(messages[0])).toBe(
`<message id="${messages[0].getAttribute('id')}" to="mercutio@montague.lit" type="chat" xmlns="jabber:client">`+
`<active xmlns="http://jabber.org/protocol/chatstates"/>`+
`<no-store xmlns="urn:xmpp:hints"/>`+
`<no-permanent-store xmlns="urn:xmpp:hints"/>`+
`</message>`);
expect(Strophe.serialize(messages[1])).toBe(
`<message id="${messages[1].getAttribute('id')}" to="mercutio@montague.lit" type="chat" xmlns="jabber:client">`+
`<composing xmlns="http://jabber.org/protocol/chatstates"/>`+
`<no-store xmlns="urn:xmpp:hints"/>`+
`<no-permanent-store xmlns="urn:xmpp:hints"/>`+
`</message>`);
expect(Strophe.serialize(messages[2])).toBe(
`<message id="${messages[2].getAttribute('id')}" to="mercutio@montague.lit" type="chat" xmlns="jabber:client">`+
`<paused xmlns="http://jabber.org/protocol/chatstates"/>`+
`<no-store xmlns="urn:xmpp:hints"/>`+
`<no-permanent-store xmlns="urn:xmpp:hints"/>`+
`</message>`);
expect(Strophe.serialize(messages[3])).toBe(
`<message id="${messages[3].getAttribute('id')}" to="mercutio@montague.lit" type="chat" xmlns="jabber:client">`+
`<inactive xmlns="http://jabber.org/protocol/chatstates"/>`+
`<no-store xmlns="urn:xmpp:hints"/>`+
`<no-permanent-store xmlns="urn:xmpp:hints"/>`+
`</message>`);
done();
}));
......
......@@ -374,7 +374,6 @@ converse.plugins.add('converse-chatview', {
initDebounced () {
this.scrollDown = _.debounce(this._scrollDown, 100);
this.markScrolled = _.debounce(this._markScrolled, 100);
this.show = _.debounce(this._show, 500, {'leading': true});
},
render () {
......@@ -1280,7 +1279,7 @@ converse.plugins.add('converse-chatview', {
}
},
emitFocused: _.debounce(() => {
emitFocused () {
/**
* Triggered when the focus has been moved to a particular chat.
* @event _converse#chatBoxFocused
......@@ -1288,11 +1287,11 @@ converse.plugins.add('converse-chatview', {
* @example _converse.api.listen.on('chatBoxFocused', view => { ... });
*/
_converse.api.trigger('chatBoxFocused', this);
}, 25, {'leading': true}),
},
focus () {
const textarea_el = this.el.querySelector('.chat-textarea');
if (!_.isNull(textarea_el)) {
const textarea_el = this.el.getElementsByClassName('chat-textarea')[0];
if (textarea_el && document.activeElement !== textarea_el) {
textarea_el.focus();
this.emitFocused();
}
......@@ -1311,18 +1310,30 @@ converse.plugins.add('converse-chatview', {
if (_converse.auto_focus) {
this.focus();
}
this.focus();
},
_show () {
/* Inner show method that gets debounced */
show () {
if (u.isVisible(this.el)) {
if (_converse.auto_focus) {
this.focus();
}
return;
}
u.fadeIn(this.el, _.bind(this.afterShown, this));
/**
* Triggered just before a {@link _converse.ChatBoxView} or {@link _converse.ChatRoomView}
* will be shown.
* @event _converse#beforeShowingChatView
* @type {object}
* @property { _converse.ChatBoxView | _converse.ChatRoomView } view
*/
_converse.api.trigger('beforeShowingChatView', this);
if (_converse.animate) {
u.fadeIn(this.el, () => this.afterShown());
} else {
u.showElement(this.el);
this.afterShown();
}
},
showNewMessagesIndicator () {
......@@ -1395,7 +1406,7 @@ converse.plugins.add('converse-chatview', {
onWindowStateChanged (state) {
if (state === 'visible') {
if (!this.model.isHidden()) {
this.model.setChatState(_converse.ACTIVE);
// this.model.setChatState(_converse.ACTIVE);
if (this.model.get('num_unread', 0)) {
this.model.clearUnreadMsgCounter();
}
......
......@@ -72,11 +72,6 @@ converse.plugins.add('converse-dragresize', {
renderDragResizeHandles(this.__super__._converse, this);
this.setWidth();
return result;
},
_show () {
this.initDragResize().setDimensions();
this.__super__._show.apply(this, arguments);
}
},
......@@ -155,12 +150,12 @@ converse.plugins.add('converse-dragresize', {
/* Determine and store the default box size.
* We need this information for the drag-resizing feature.
*/
const flyout = this.el.querySelector('.box-flyout'),
style = window.getComputedStyle(flyout);
const flyout = this.el.querySelector('.box-flyout');
const style = window.getComputedStyle(flyout);
if (_.isUndefined(this.model.get('height'))) {
const height = parseInt(style.height.replace(/px$/, ''), 10),
width = parseInt(style.width.replace(/px$/, ''), 10);
const height = parseInt(style.height.replace(/px$/, ''), 10);
const width = parseInt(style.width.replace(/px$/, ''), 10);
this.model.set('height', height);
this.model.set('default_height', height);
this.model.set('width', width);
......@@ -341,6 +336,7 @@ converse.plugins.add('converse-dragresize', {
}
_converse.api.listen.on('registeredGlobalEventHandlers', registerGlobalEventHandlers);
_converse.api.listen.on('beforeShowingChatView', view => view.initDragResize().setDimensions());
_converse.api.listen.on('chatBoxInitialized', view => {
window.addEventListener('resize', _.debounce(() => view.setDimensions(), 100));
......
......@@ -78,18 +78,22 @@ converse.plugins.add('converse-minimize', {
return this.__super__.initialize.apply(this, arguments);
},
_show () {
show () {
const { _converse } = this.__super__;
if (_converse.view_mode !== 'overlayed') {
return this.__super__._show.apply(this, arguments);
} else if (!this.model.get('minimized')) {
this.__super__._show.apply(this, arguments);
_converse.chatboxviews.trimChats(this);
} else {
if (_converse.view_mode === 'overlayed' && this.model.get('minimized')) {
this.model.minimize();
return this;
} else {
return this.__super__.show.apply(this, arguments);
}
},
afterShown () {
const { _converse } = this.__super__;
this.__super__.afterShown.apply(this, arguments);
_converse.chatboxviews.trimChats(this);
},
isNewMessageHidden () {
return this.model.get('minimized') ||
this.__super__.isNewMessageHidden.apply(this, arguments);
......
......@@ -701,19 +701,6 @@ converse.plugins.add('converse-muc-views', {
this.renderEmojiPicker();
},
show () {
if (u.isVisible(this.el)) {
if (_converse.auto_focus) {
this.focus();
}
return;
}
// Override from converse-chatview in order to not use
// "fadeIn", which causes flashing.
u.showElement(this.el);
this.afterShown();
},
onConnectionStatusChanged () {
const conn_status = this.model.get('connection_status');
if (conn_status === converse.ROOMSTATUS.NICKNAME_REQUIRED) {
......
......@@ -75,31 +75,32 @@ converse.plugins.add('converse-uniview', {
} else {
return this.__super__.shouldShowOnTextMessage.apply(this, arguments);
}
},
_show (focus) {
/* We only have one chat visible at any one
* time. So before opening a chat, we make sure all other
* chats are hidden.
*/
const { _converse } = this.__super__;
if (_converse.isUniView()) {
_.each(this.__super__._converse.chatboxviews.xget(this.model.get('id')), hideChat);
u.safeSave(this.model, {'hidden': false});
}
return this.__super__._show.apply(this, arguments);
}
},
}
},
ChatRoomView: {
show (focus) {
const { _converse } = this.__super__;
if (_converse.isUniView()) {
_.each(this.__super__._converse.chatboxviews.xget(this.model.get('id')), hideChat);
u.safeSave(this.model, {'hidden': false});
initialize () {
/* The initialize function gets called as soon as the plugin is
* loaded by converse.js's plugin machinery.
*/
const { _converse } = this;
/************************ BEGIN Event Handlers ************************/
_converse.api.listen.on('beforeShowingChatView', (view) => {
/* We only have one chat visible at any one
* time. So before opening a chat, we make sure all other
* chats are hidden.
*/
if (_converse.isUniView()) {
Object.values(_converse.chatboxviews.xget(view.model.get('id')))
.filter(v => !v.model.get('hidden'))
.forEach(hideChat);
if (view.model.get('hidden')) {
u.safeSave(view.model, {'hidden': false});
}
return this.__super__.show.apply(this, arguments);
}
}
});
/************************ END Event Handlers ************************/
}
});
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment