Commit 9528d81c authored by JC Brand's avatar JC Brand

Move various MUC methods onto the Backbone.Model

To more cleanly separate views and models and to make MUC in headless
mode more viable.

Refs #1032
parent b0c22d98
......@@ -4,8 +4,8 @@
## UI changes
* The UI is now based on Bootstrap4 and Flexbox is used extensively.
* #956 Conversation pane should show my own identity in pane header
- The UI is now based on Bootstrap4 and Flexbox is used extensively.
- #956 Conversation pane should show my own identity in pane header
## New Features
......@@ -13,15 +13,21 @@
## Configuration changes
* Removed the `xhr_custom_status` and `xhr_custom_status_url` configuration
- Removed the `xhr_custom_status` and `xhr_custom_status_url` configuration
settings. If you relied on these settings, you can instead listen for the
[statusMessageChanged](https://conversejs.org/docs/html/events.html#contactstatusmessagechanged)
event and make the XMLHttpRequest yourself.
* Removed `xhr_user_search` in favor of only accepting `xhr_user_search_url` as configuration option.
* The data returned from the `xhr_user_search_url` must now include the user's
- Removed `xhr_user_search` in favor of only accepting `xhr_user_search_url` as configuration option.
- The data returned from the `xhr_user_search_url` must now include the user's
`jid` instead of just an `id`.
- New configuration setting [nickname](https://conversejs.org/docs/html/configurations.html#nickname)
## Architectural changes
- Extracted the views from `converse-muc.js` into `converse-muc-views.js` and
where appropriate moved methods from the views into the models/collections.
This makes MUC possible in headless mode.
### Bugfixes
- Spoiler messages didn't include the message author's name.
......
......@@ -7594,6 +7594,9 @@ body.reset {
#converse-embedded-chat .chatbox .sendXMPPMessage .chat-toolbar li .toolbar-menu ul li.insert-emoji a:hover,
#conversejs .chatbox .sendXMPPMessage .chat-toolbar li .toolbar-menu ul li.insert-emoji a:hover {
color: #8f2831; }
#converse-embedded-chat .chatbox .sendXMPPMessage .chat-toolbar li.toggle-smiley a.toggle-smiley,
#conversejs .chatbox .sendXMPPMessage .chat-toolbar li.toggle-smiley a.toggle-smiley {
padding: 0; }
#converse-embedded-chat .chatbox .sendXMPPMessage .chat-toolbar li.toggle-smiley .emoji-toolbar,
#conversejs .chatbox .sendXMPPMessage .chat-toolbar li.toggle-smiley .emoji-toolbar {
box-shadow: 0 -1px 1px 0 rgba(0, 0, 0, 0.4); }
......
......@@ -7647,28 +7647,31 @@ body {
#converse-embedded-chat .chatbox .sendXMPPMessage .chat-toolbar li .toolbar-menu ul li.insert-emoji a:hover,
#conversejs .chatbox .sendXMPPMessage .chat-toolbar li .toolbar-menu ul li.insert-emoji a:hover {
color: #8f2831; }
#converse-embedded-chat .chatbox .sendXMPPMessage .chat-toolbar li.toggle-smiley .emoji-toolbar,
#conversejs .chatbox .sendXMPPMessage .chat-toolbar li.toggle-smiley .emoji-toolbar {
box-shadow: 0 -1px 1px 0 rgba(0, 0, 0, 0.4); }
#converse-embedded-chat .chatbox .sendXMPPMessage .chat-toolbar li.toggle-smiley .emoji-toolbar .emoji-category-picker,
#conversejs .chatbox .sendXMPPMessage .chat-toolbar li.toggle-smiley .emoji-toolbar .emoji-category-picker {
padding-top: 0.5em; }
#converse-embedded-chat .chatbox .sendXMPPMessage .chat-toolbar li.toggle-smiley .emoji-toolbar .emoji-category-picker ul,
#conversejs .chatbox .sendXMPPMessage .chat-toolbar li.toggle-smiley .emoji-toolbar .emoji-category-picker ul {
display: flex;
flex-direction: row;
justify-content: space-between; }
#converse-embedded-chat .chatbox .sendXMPPMessage .chat-toolbar li.toggle-smiley .emoji-toolbar .emoji-category-picker li,
#converse-embedded-chat .chatbox .sendXMPPMessage .chat-toolbar li.toggle-smiley .emoji-toolbar .emoji-skintone-picker li,
#conversejs .chatbox .sendXMPPMessage .chat-toolbar li.toggle-smiley .emoji-toolbar .emoji-category-picker li,
#conversejs .chatbox .sendXMPPMessage .chat-toolbar li.toggle-smiley .emoji-toolbar .emoji-skintone-picker li {
padding: 0.2em;
font-size: 26px; }
#converse-embedded-chat .chatbox .sendXMPPMessage .chat-toolbar li.toggle-smiley .emoji-toolbar .emoji-category-picker li:hover,
#converse-embedded-chat .chatbox .sendXMPPMessage .chat-toolbar li.toggle-smiley .emoji-toolbar .emoji-skintone-picker li:hover,
#conversejs .chatbox .sendXMPPMessage .chat-toolbar li.toggle-smiley .emoji-toolbar .emoji-category-picker li:hover,
#conversejs .chatbox .sendXMPPMessage .chat-toolbar li.toggle-smiley .emoji-toolbar .emoji-skintone-picker li:hover {
background-color: #DCF9F6; }
#converse-embedded-chat .chatbox .sendXMPPMessage .chat-toolbar li.toggle-smiley,
#conversejs .chatbox .sendXMPPMessage .chat-toolbar li.toggle-smiley {
padding: 0 0 0 0.5em; }
#converse-embedded-chat .chatbox .sendXMPPMessage .chat-toolbar li.toggle-smiley .emoji-toolbar,
#conversejs .chatbox .sendXMPPMessage .chat-toolbar li.toggle-smiley .emoji-toolbar {
box-shadow: 0 -1px 1px 0 rgba(0, 0, 0, 0.4); }
#converse-embedded-chat .chatbox .sendXMPPMessage .chat-toolbar li.toggle-smiley .emoji-toolbar .emoji-category-picker,
#conversejs .chatbox .sendXMPPMessage .chat-toolbar li.toggle-smiley .emoji-toolbar .emoji-category-picker {
padding-top: 0.5em; }
#converse-embedded-chat .chatbox .sendXMPPMessage .chat-toolbar li.toggle-smiley .emoji-toolbar .emoji-category-picker ul,
#conversejs .chatbox .sendXMPPMessage .chat-toolbar li.toggle-smiley .emoji-toolbar .emoji-category-picker ul {
display: flex;
flex-direction: row;
justify-content: space-between; }
#converse-embedded-chat .chatbox .sendXMPPMessage .chat-toolbar li.toggle-smiley .emoji-toolbar .emoji-category-picker li,
#converse-embedded-chat .chatbox .sendXMPPMessage .chat-toolbar li.toggle-smiley .emoji-toolbar .emoji-skintone-picker li,
#conversejs .chatbox .sendXMPPMessage .chat-toolbar li.toggle-smiley .emoji-toolbar .emoji-category-picker li,
#conversejs .chatbox .sendXMPPMessage .chat-toolbar li.toggle-smiley .emoji-toolbar .emoji-skintone-picker li {
padding: 0.2em;
font-size: 26px; }
#converse-embedded-chat .chatbox .sendXMPPMessage .chat-toolbar li.toggle-smiley .emoji-toolbar .emoji-category-picker li:hover,
#converse-embedded-chat .chatbox .sendXMPPMessage .chat-toolbar li.toggle-smiley .emoji-toolbar .emoji-skintone-picker li:hover,
#conversejs .chatbox .sendXMPPMessage .chat-toolbar li.toggle-smiley .emoji-toolbar .emoji-category-picker li:hover,
#conversejs .chatbox .sendXMPPMessage .chat-toolbar li.toggle-smiley .emoji-toolbar .emoji-skintone-picker li:hover {
background-color: #DCF9F6; }
#converse-embedded-chat .chatbox .sendXMPPMessage .chat-toolbar li.toggle-otr ul,
#conversejs .chatbox .sendXMPPMessage .chat-toolbar li.toggle-otr ul {
z-index: 99; }
......@@ -7788,13 +7791,11 @@ body {
line-height: 26px; }
#conversejs.fullscreen .chatbox .sendXMPPMessage ul {
width: 100%; }
#conversejs.fullscreen .chatbox .sendXMPPMessage .toggle-smiley {
padding-left: 0.5em; }
#conversejs.fullscreen .chatbox .sendXMPPMessage .toggle-smiley ul.emoji-toolbar .emoji-category-picker {
margin-right: 5em; }
#conversejs.fullscreen .chatbox .sendXMPPMessage .toggle-smiley ul.emoji-toolbar .emoji-category {
padding-left: 10px;
padding-right: 10px; }
#conversejs.fullscreen .chatbox .sendXMPPMessage .toggle-smiley ul.emoji-toolbar .emoji-category-picker {
margin-right: 5em; }
#conversejs.fullscreen .chatbox .sendXMPPMessage .toggle-smiley ul.emoji-toolbar .emoji-category {
padding-left: 10px;
padding-right: 10px; }
@media screen and (max-width: 767px) {
#conversejs.fullscreen .chatbox {
......
......@@ -34,8 +34,8 @@ For more info on how to use (or add promises), you can read the
Below we will now list all events and also specify whether they are available
as promises.
List of Events (and promises)
-----------------------------
List of global events (and promises)
------------------------------------
Hooking into events that Converse.js emits is a great way to extend or
customize its functionality.
......@@ -478,3 +478,16 @@ windowStateChanged
When window state has changed. Used to determine when a user left the page and when came back.
``_converse.on('windowStateChanged', function (data) { ... });``
List of events on the ChatRoom Backbone.Model
---------------------------------------------
configurationNeeded
~~~~~~~~~~~~~~~~~~~
Triggered when a new room has been created which first needs to be configured
and when `auto_configure` is set to `false`.
Used by the core `ChatRoomView` view in order to know when to render the
configuration form for a new room.
......@@ -433,6 +433,9 @@
}
}
&.toggle-smiley {
a.toggle-smiley {
padding: 0;
}
.emoji-toolbar {
box-shadow: 0 -1px 1px 0 rgba(0, 0, 0, 0.4);
......
......@@ -78,7 +78,6 @@
width: 100%;
}
.toggle-smiley {
padding-left: 0.5em;
ul {
&.emoji-toolbar {
.emoji-category-picker {
......
This diff is collapsed.
......@@ -39,7 +39,7 @@
</forwarded>
</result>
</message>`).firstElementChild;
chatroomview.onChatRoomMessage(stanza);
chatroomview.model.onMessage(stanza);
expect(chatroomview.content.querySelectorAll('.chat-message').length).toBe(1);
done();
});
......
......@@ -158,7 +158,7 @@
to: 'dummy@localhost',
type: 'groupchat'
}).c('body').t(message).tree();
view.handleMUCMessage(msg);
view.model.onMessage(msg);
expect($(_converse.minimized_chats.toggleview.el.querySelector('.unread-message-count')).is(':visible')).toBeTruthy();
expect($(_converse.minimized_chats.toggleview.el.querySelector('.unread-message-count')).text()).toBe('1');
......
......@@ -173,7 +173,7 @@
to: 'dummy@localhost',
type: 'groupchat'
}).c('body').t(text);
view.onChatRoomMessage(message.nodeTree);
view.model.onMessage(message.nodeTree);
expect(_converse.playSoundNotification).toHaveBeenCalled();
text = "This message won't play a sound";
......@@ -183,7 +183,7 @@
to: 'dummy@localhost',
type: 'groupchat'
}).c('body').t(text);
view.onChatRoomMessage(message.nodeTree);
view.model.onMessage(message.nodeTree);
expect(_converse.playSoundNotification, 1);
_converse.play_sounds = false;
......@@ -194,7 +194,7 @@
to: 'dummy@localhost',
type: 'groupchat'
}).c('body').t(text);
view.onChatRoomMessage(message.nodeTree);
view.model.onMessage(message.nodeTree);
expect(_converse.playSoundNotification, 1);
_converse.play_sounds = false;
done();
......
......@@ -97,7 +97,7 @@
view.model.set({'minimized': true});
var contact_jid = mock.cur_names[5].replace(/ /g,'.').toLowerCase() + '@localhost';
var nick = mock.chatroom_names[0];
view.handleMUCMessage(
view.model.onMessage(
$msg({
from: room_jid+'/'+nick,
id: (new Date()).getTime(),
......@@ -112,7 +112,7 @@
expect(_.includes(room_el.classList, 'unread-msgs'));
// If the user is mentioned, the counter also gets updated
view.handleMUCMessage(
view.model.onMessage(
$msg({
from: room_jid+'/'+nick,
id: (new Date()).getTime(),
......@@ -123,7 +123,7 @@
var indicator_el = _converse.rooms_list_view.el.querySelector(".msgs-indicator");
expect(indicator_el.textContent).toBe('1');
view.handleMUCMessage(
view.model.onMessage(
$msg({
from: room_jid+'/'+nick,
id: (new Date()).getTime(),
......
......@@ -416,6 +416,7 @@
'isodate': isodate,
'data': data
}));
this.insertDayIndicator(this.content.lastElementChild);
this.scrollDown();
return isodate;
},
......
......@@ -269,13 +269,16 @@
},
},
ChatRoomView: {
ChatRoom: {
initialize () {
const { _converse } = this.__super__;
this.__super__.initialize.apply(this, arguments);
this.model.on('change:mam_enabled', this.fetchArchivedMessagesIfNecessary, this);
this.model.on('change:connection_status', this.fetchArchivedMessagesIfNecessary, this);
onMessage (stanza) {
/* MAM (message archive management XEP-0313) messages are
* ignored, since they're handled separately.
*/
if (sizzle(`[xmlns="${Strophe.NS.MAM}"]`, stanza).length > 0) {
return true;
}
return this.__super__.onMessage.apply(this, arguments);
},
isDuplicate (message, original_stanza) {
......@@ -285,8 +288,18 @@
}
const archive_id = getMessageArchiveID(original_stanza);
if (archive_id) {
return this.model.messages.filter({'archive_id': archive_id}).length > 0;
return this.messages.filter({'archive_id': archive_id}).length > 0;
}
}
},
ChatRoomView: {
initialize () {
const { _converse } = this.__super__;
this.__super__.initialize.apply(this, arguments);
this.model.on('change:mam_enabled', this.fetchArchivedMessagesIfNecessary, this);
this.model.on('change:connection_status', this.fetchArchivedMessagesIfNecessary, this);
},
renderChatArea () {
......@@ -297,16 +310,6 @@
return result;
},
handleMUCMessage (stanza) {
/* MAM (message archive management XEP-0313) messages are
* ignored, since they're handled separately.
*/
if (sizzle(`[xmlns="${Strophe.NS.MAM}"]`, stanza).length > 0) {
return true;
}
return this.__super__.handleMUCMessage.apply(this, arguments);
},
fetchArchivedMessagesIfNecessary () {
if (this.model.get('connection_status') !== converse.ROOMSTATUS.ENTERED ||
!this.model.get('mam_enabled') ||
......@@ -321,7 +324,7 @@
fetchArchivedMessages (options) {
/* Fetch archived chat messages for this Chat Room
*
* Then, upon receiving them, call onChatRoomMessage
* Then, upon receiving them, call onMessage
* so that they are displayed inside it.
*/
const that = this;
......@@ -337,7 +340,7 @@
function (messages) {
that.clearSpinner();
if (messages.length) {
_.each(messages, that.onChatRoomMessage.bind(that));
_.each(messages, that.model.onMessage.bind(that));
}
},
function () {
......@@ -363,7 +366,6 @@
message_archiving_timeout: 8000, // Time (in milliseconds) to wait before aborting MAM request
});
_converse.onMAMError = function (iq) {
if (iq.querySelectorAll('feature-not-implemented').length) {
_converse.log(
......
This diff is collapsed.
This diff is collapsed.
......@@ -213,7 +213,8 @@
const name = ev.target.getAttribute('data-room-name');
const jid = ev.target.getAttribute('data-room-jid');
if (confirm(__("Are you sure you want to leave the room %1$s?", name))) {
_converse.chatboxviews.get(jid).leave();
// TODO: replace with API call
_converse.chatboxviews.get(jid).close();
}
},
......
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