diff --git a/spec/chatbox.js b/spec/chatbox.js
index bf83e560c..b41561220 100644
--- a/spec/chatbox.js
+++ b/spec/chatbox.js
@@ -419,7 +419,7 @@
expect(view).toBeDefined();
var $toolbar = $(view.el).find('ul.chat-toolbar');
expect($toolbar.length).toBe(1);
- expect($toolbar.children('li').length).toBe(4);
+ expect($toolbar.children('li').length).toBe(3);
done();
}));
diff --git a/spec/otr.js b/spec/otr.js
index 57f403307..f868319d0 100644
--- a/spec/otr.js
+++ b/spec/otr.js
@@ -3,6 +3,8 @@
} (this, function ($, jasmine, mock, converse, test_utils) {
var Strophe = converse.env.Strophe;
var b64_sha1 = converse.env.b64_sha1;
+ var $pres = converse.env.$pres;
+ var _ = converse.env._;
describe("A chatbox with an active OTR session", function() {
@@ -13,28 +15,57 @@
test_utils.createContacts(_converse, 'current');
var contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@localhost';
+
+ // XXX: We need to send a presence from the contact, so that we
+ // have a resource, that resource is then queried to see
+ // whether Strophe.NS.SPOILER is supported, in which case
+ // the spoiler button will appear.
+ var presence = $pres({
+ 'from': contact_jid+'/phone',
+ 'to': 'dummy@localhost'
+ });
+ _converse.connection._dataRecv(test_utils.createRequest(presence));
test_utils.openChatBoxFor(_converse, contact_jid);
- var view = _converse.chatboxviews.get(contact_jid);
- var spoiler_toggle = view.el.querySelector('.toggle-compose-spoiler');
- expect(spoiler_toggle).not.toBe(null);
+ test_utils.waitUntilDiscoConfirmed(_converse, contact_jid+'/phone', [], [Strophe.NS.SPOILER]).then(function () {
+ var spoiler_toggle;
+ var view = _converse.chatboxviews.get(contact_jid);
+ spyOn(view, 'addSpoilerButton').and.callThrough();
+ view.model.set('otr_status', 1);
- view.model.set('otr_status', 0);
- spoiler_toggle = view.el.querySelector('.toggle-compose-spoiler');
- expect(spoiler_toggle).not.toBe(null);
+ test_utils.waitUntil(function () {
+ return _.isNull(view.el.querySelector('.toggle-compose-spoiler'));
+ }).then(function () {
+ spoiler_toggle = view.el.querySelector('.toggle-compose-spoiler');
+ expect(spoiler_toggle).toBe(null);
- view.model.set('otr_status', 1);
- spoiler_toggle = view.el.querySelector('.toggle-compose-spoiler');
- expect(spoiler_toggle).toBe(null);
+ view.model.set('otr_status', 3);
- view.model.set('otr_status', 2);
- spoiler_toggle = view.el.querySelector('.toggle-compose-spoiler');
- expect(spoiler_toggle).toBe(null);
+ return test_utils.waitUntil(function () {
+ return !_.isNull(view.el.querySelector('.toggle-compose-spoiler'));
+ });
+ }).then(function () {
+ spoiler_toggle = view.el.querySelector('.toggle-compose-spoiler');
+ expect(spoiler_toggle).not.toBe(null);
- view.model.set('otr_status', 3);
- spoiler_toggle = view.el.querySelector('.toggle-compose-spoiler');
- expect(spoiler_toggle).not.toBe(null);
- done();
+ view.model.set('otr_status', 2);
+ return test_utils.waitUntil(function () {
+ return _.isNull(view.el.querySelector('.toggle-compose-spoiler'));
+ });
+ }).then(function () {
+ spoiler_toggle = view.el.querySelector('.toggle-compose-spoiler');
+ expect(spoiler_toggle).toBe(null);
+
+ view.model.set('otr_status', 4);
+ return test_utils.waitUntil(function () {
+ return !_.isNull(view.el.querySelector('.toggle-compose-spoiler'));
+ });
+ }).then(function () {
+ spoiler_toggle = view.el.querySelector('.toggle-compose-spoiler');
+ expect(spoiler_toggle).not.toBe(null);
+ done();
+ });
+ });
}));
});
diff --git a/spec/spoilers.js b/spec/spoilers.js
index cdd1e25ce..6a8992cd7 100644
--- a/spec/spoilers.js
+++ b/spec/spoilers.js
@@ -9,7 +9,9 @@
} (this, function (jasmine, utils, mock, converse, test_utils) {
var _ = converse.env._;
+ var Strophe = converse.env.Strophe;
var $msg = converse.env.$msg;
+ var $pres = converse.env.$pres;
var u = converse.env.utils;
return describe("A spoiler message", function () {
@@ -93,57 +95,69 @@
test_utils.openControlBox();
test_utils.openContactsPanel(_converse);
var contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@localhost';
+
+ // XXX: We need to send a presence from the contact, so that we
+ // have a resource, that resource is then queried to see
+ // whether Strophe.NS.SPOILER is supported, in which case
+ // the spoiler button will appear.
+ var presence = $pres({
+ 'from': contact_jid+'/phone',
+ 'to': 'dummy@localhost'
+ });
+ _converse.connection._dataRecv(test_utils.createRequest(presence));
test_utils.openChatBoxFor(_converse, contact_jid);
- var view = _converse.chatboxviews.get(contact_jid);
- spyOn(view, 'onMessageSubmitted').and.callThrough();
- spyOn(_converse.connection, 'send');
+ test_utils.waitUntilDiscoConfirmed(_converse, contact_jid+'/phone', [], [Strophe.NS.SPOILER]).then(function () {
+ var view = _converse.chatboxviews.get(contact_jid);
+ spyOn(view, 'onMessageSubmitted').and.callThrough();
+ spyOn(_converse.connection, 'send');
- var spoiler_toggle = view.el.querySelector('.toggle-compose-spoiler');
- spoiler_toggle.click();
+ var spoiler_toggle = view.el.querySelector('.toggle-compose-spoiler');
+ spoiler_toggle.click();
- var textarea = view.el.querySelector('.chat-textarea');
- textarea.value = 'This is the spoiler';
- view.keyPressed({
- target: textarea,
- preventDefault: _.noop,
- keyCode: 13
+ var textarea = view.el.querySelector('.chat-textarea');
+ textarea.value = 'This is the spoiler';
+ view.keyPressed({
+ target: textarea,
+ preventDefault: _.noop,
+ keyCode: 13
+ });
+ expect(view.onMessageSubmitted).toHaveBeenCalled();
+
+ /* Test the XML stanza
+ *
+ *
+ * This is the spoiler
+ *
+ *
+ * "
+ */
+ var stanza = _converse.connection.send.calls.argsFor(0)[0].tree();
+ var spoiler_el = stanza.querySelector('spoiler[xmlns="urn:xmpp:spoiler:0"]');
+ expect(_.isNull(spoiler_el)).toBeFalsy();
+ expect(spoiler_el.textContent).toBe('');
+
+ var body_el = stanza.querySelector('body');
+ expect(body_el.textContent).toBe('This is the spoiler');
+
+ /* Test the HTML spoiler message */
+ var spoiler_msg_el = view.el.querySelector('.chat-msg-content.spoiler');
+ expect(spoiler_msg_el.textContent).toBe('This is the spoiler');
+ expect(_.includes(spoiler_msg_el.classList, 'collapsed')).toBeTruthy();
+
+ spoiler_toggle = view.el.querySelector('.toggle-spoiler');
+ expect(spoiler_toggle.textContent).toBe('Show hidden message');
+ spoiler_toggle.click();
+ expect(_.includes(spoiler_msg_el.classList, 'collapsed')).toBeFalsy();
+ expect(spoiler_toggle.textContent).toBe('Hide hidden message');
+ spoiler_toggle.click();
+ expect(_.includes(spoiler_msg_el.classList, 'collapsed')).toBeTruthy();
+ done();
});
- expect(view.onMessageSubmitted).toHaveBeenCalled();
-
- /* Test the XML stanza
- *
- *
- * This is the spoiler
- *
- *
- * "
- */
- var stanza = _converse.connection.send.calls.argsFor(0)[0].tree();
- var spoiler_el = stanza.querySelector('spoiler[xmlns="urn:xmpp:spoiler:0"]');
- expect(_.isNull(spoiler_el)).toBeFalsy();
- expect(spoiler_el.textContent).toBe('');
-
- var body_el = stanza.querySelector('body');
- expect(body_el.textContent).toBe('This is the spoiler');
-
- /* Test the HTML spoiler message */
- var spoiler_msg_el = view.el.querySelector('.chat-msg-content.spoiler');
- expect(spoiler_msg_el.textContent).toBe('This is the spoiler');
- expect(_.includes(spoiler_msg_el.classList, 'collapsed')).toBeTruthy();
-
- spoiler_toggle = view.el.querySelector('.toggle-spoiler');
- expect(spoiler_toggle.textContent).toBe('Show hidden message');
- spoiler_toggle.click();
- expect(_.includes(spoiler_msg_el.classList, 'collapsed')).toBeFalsy();
- expect(spoiler_toggle.textContent).toBe('Hide hidden message');
- spoiler_toggle.click();
- expect(_.includes(spoiler_msg_el.classList, 'collapsed')).toBeTruthy();
- done();
}));
it("can be sent with a hint",
@@ -155,61 +169,72 @@
test_utils.openControlBox();
test_utils.openContactsPanel(_converse);
var contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@localhost';
+
+ // XXX: We need to send a presence from the contact, so that we
+ // have a resource, that resource is then queried to see
+ // whether Strophe.NS.SPOILER is supported, in which case
+ // the spoiler button will appear.
+ var presence = $pres({
+ 'from': contact_jid+'/phone',
+ 'to': 'dummy@localhost'
+ });
+ _converse.connection._dataRecv(test_utils.createRequest(presence));
test_utils.openChatBoxFor(_converse, contact_jid);
- var view = _converse.chatboxviews.get(contact_jid);
+ test_utils.waitUntilDiscoConfirmed(_converse, contact_jid+'/phone', [], [Strophe.NS.SPOILER]).then(function () {
+ var view = _converse.chatboxviews.get(contact_jid);
+ var spoiler_toggle = view.el.querySelector('.toggle-compose-spoiler');
+ spoiler_toggle.click();
- var spoiler_toggle = view.el.querySelector('.toggle-compose-spoiler');
- spoiler_toggle.click();
+ spyOn(view, 'onMessageSubmitted').and.callThrough();
+ spyOn(_converse.connection, 'send');
- spyOn(view, 'onMessageSubmitted').and.callThrough();
- spyOn(_converse.connection, 'send');
+ var textarea = view.el.querySelector('.chat-textarea');
+ textarea.value = 'This is the spoiler';
+ var hint_input = view.el.querySelector('.spoiler-hint');
+ hint_input.value = 'This is the hint';
- var textarea = view.el.querySelector('.chat-textarea');
- textarea.value = 'This is the spoiler';
- var hint_input = view.el.querySelector('.spoiler-hint');
- hint_input.value = 'This is the hint';
+ view.keyPressed({
+ target: textarea,
+ preventDefault: _.noop,
+ keyCode: 13
+ });
+ expect(view.onMessageSubmitted).toHaveBeenCalled();
- view.keyPressed({
- target: textarea,
- preventDefault: _.noop,
- keyCode: 13
+ /* Test the XML stanza
+ *
+ *
+ * This is the spoiler
+ *
+ * This is the hint
+ * "
+ */
+ var stanza = _converse.connection.send.calls.argsFor(0)[0].tree();
+ var spoiler_el = stanza.querySelector('spoiler[xmlns="urn:xmpp:spoiler:0"]');
+ expect(_.isNull(spoiler_el)).toBeFalsy();
+ expect(spoiler_el.textContent).toBe('This is the hint');
+
+ var body_el = stanza.querySelector('body');
+ expect(body_el.textContent).toBe('This is the spoiler');
+
+ /* Test the HTML spoiler message */
+ var spoiler_msg_el = view.el.querySelector('.chat-msg-content.spoiler');
+ expect(spoiler_msg_el.textContent).toBe('This is the spoiler');
+ expect(_.includes(spoiler_msg_el.classList, 'collapsed')).toBeTruthy();
+
+ spoiler_toggle = view.el.querySelector('.toggle-spoiler');
+ expect(spoiler_toggle.textContent).toBe('Show hidden message');
+ spoiler_toggle.click();
+ expect(_.includes(spoiler_msg_el.classList, 'collapsed')).toBeFalsy();
+ expect(spoiler_toggle.textContent).toBe('Hide hidden message');
+ spoiler_toggle.click();
+ expect(_.includes(spoiler_msg_el.classList, 'collapsed')).toBeTruthy();
+ done();
});
- expect(view.onMessageSubmitted).toHaveBeenCalled();
-
- /* Test the XML stanza
- *
- *
- * This is the spoiler
- *
- * This is the hint
- * "
- */
- var stanza = _converse.connection.send.calls.argsFor(0)[0].tree();
- var spoiler_el = stanza.querySelector('spoiler[xmlns="urn:xmpp:spoiler:0"]');
- expect(_.isNull(spoiler_el)).toBeFalsy();
- expect(spoiler_el.textContent).toBe('This is the hint');
-
- var body_el = stanza.querySelector('body');
- expect(body_el.textContent).toBe('This is the spoiler');
-
- /* Test the HTML spoiler message */
- var spoiler_msg_el = view.el.querySelector('.chat-msg-content.spoiler');
- expect(spoiler_msg_el.textContent).toBe('This is the spoiler');
- expect(_.includes(spoiler_msg_el.classList, 'collapsed')).toBeTruthy();
-
- spoiler_toggle = view.el.querySelector('.toggle-spoiler');
- expect(spoiler_toggle.textContent).toBe('Show hidden message');
- spoiler_toggle.click();
- expect(_.includes(spoiler_msg_el.classList, 'collapsed')).toBeFalsy();
- expect(spoiler_toggle.textContent).toBe('Hide hidden message');
- spoiler_toggle.click();
- expect(_.includes(spoiler_msg_el.classList, 'collapsed')).toBeTruthy();
- done();
}));
});
}));
diff --git a/src/converse-chatview.js b/src/converse-chatview.js
index 8a3486eff..3b91988d6 100644
--- a/src/converse-chatview.js
+++ b/src/converse-chatview.js
@@ -22,6 +22,7 @@
"tpl!message",
"tpl!new_day",
"tpl!spinner",
+ "tpl!spoiler_button",
"tpl!spoiler_message",
"tpl!toolbar"
], factory);
@@ -40,11 +41,12 @@
tpl_message,
tpl_new_day,
tpl_spinner,
+ tpl_spoiler_button,
tpl_spoiler_message,
tpl_toolbar
) {
"use strict";
- const { $msg, Backbone, Strophe, _, b64_sha1, sizzle, moment } = converse.env;
+ const { $msg, Backbone, Promise, Strophe, _, b64_sha1, f, sizzle, moment } = converse.env;
const u = converse.env.utils;
const KEY = {
ENTER: 13,
@@ -323,6 +325,7 @@
this.getToolbarOptions(options || {})
);
this.el.querySelector('.chat-toolbar').innerHTML = toolbar(options);
+ this.addSpoilerButton(options);
this.insertEmojiPicker();
return this;
},
@@ -343,14 +346,40 @@
'label_spoiler_hint': __('Optional hint'),
'message_value': _.get(this.el.querySelector('.chat-textarea'), 'value'),
'show_send_button': _converse.show_send_button,
- 'show_spoiler_button': _converse.visible_toolbar_buttons.spoiler,
- 'show_textarea': true,
'show_toolbar': _converse.show_toolbar,
'unread_msgs': __('You have unread messages')
}));
this.renderToolbar();
},
+ addSpoilerButton (options) {
+ /* Asynchronously adds a button for writing spoiler
+ * messages, based on whether the contact's client supports
+ * it.
+ */
+ if (!options.show_spoiler_button || this.model.get('type') === 'chatroom') {
+ return;
+ }
+ const contact_jid = this.model.get('jid');
+ const resources = this.model.get('resources');
+ if (_.isEmpty(resources)) {
+ return;
+ }
+ Promise.all(_.map(_.keys(resources), (resource) =>
+ _converse.api.disco.supports(Strophe.NS.SPOILER, `${contact_jid}/${resource}`)
+ )).then((results) => {
+ const supported = _.every(f.map(f.get('supported'))(results));
+ if (supported) {
+ const html = tpl_spoiler_button(this.model.toJSON());
+ if (_converse.visible_toolbar_buttons.emoji) {
+ this.el.querySelector('.toggle-smiley').insertAdjacentHTML('afterEnd', html);
+ } else {
+ this.el.querySelector('.chat-toolbar').insertAdjacentHTML('afterBegin', html);
+ }
+ }
+ });
+ },
+
insertHeading () {
this.heading = new _converse.ChatBoxHeading({'model': this.model});
this.heading.render();
diff --git a/src/converse-core.js b/src/converse-core.js
index a6278e491..aabe1abcf 100644
--- a/src/converse-core.js
+++ b/src/converse-core.js
@@ -9,6 +9,7 @@
define(["sizzle",
"es6-promise",
"lodash.noconflict",
+ "lodash.fp",
"polyfill",
"i18n",
"utils",
@@ -19,7 +20,7 @@
"backbone.nativeview",
"backbone.browserStorage"
], factory);
-}(this, function (sizzle, Promise, _, polyfill, i18n, utils, moment, Strophe, pluggable, Backbone) {
+}(this, function (sizzle, Promise, _, f, polyfill, i18n, utils, moment, Strophe, pluggable, Backbone) {
/* Cannot use this due to Safari bug.
* See https://github.com/jcbrand/converse.js/issues/196
@@ -972,6 +973,7 @@
const resources = _.isObject(this.get('resources')) ? this.get('resources') : {};
resources[resource] = {
+ 'name': resource,
'priority': priority,
'status': chat_status,
'timestamp': timestamp
@@ -2019,6 +2021,7 @@
'Promise': Promise,
'Strophe': Strophe,
'_': _,
+ 'f': f,
'b64_sha1': b64_sha1,
'moment': moment,
'sizzle': sizzle,
diff --git a/src/converse-headline.js b/src/converse-headline.js
index 78169ef95..63ef06b05 100644
--- a/src/converse-headline.js
+++ b/src/converse-headline.js
@@ -146,8 +146,7 @@
}
function registerHeadlineHandler () {
- _converse.connection.addHandler(
- onHeadlineMessage, null, 'message');
+ _converse.connection.addHandler(onHeadlineMessage, null, 'message');
}
_converse.on('connected', registerHeadlineHandler);
_converse.on('reconnected', registerHeadlineHandler);
diff --git a/src/converse-mam.js b/src/converse-mam.js
index 40df3367f..a72a9f791 100644
--- a/src/converse-mam.js
+++ b/src/converse-mam.js
@@ -83,7 +83,7 @@
}
const messages = [];
- const message_handler = _converse.connection.addHandler(function (message) {
+ const message_handler = _converse.connection.addHandler((message) => {
if (options.groupchat && message.getAttribute('from') !== options['with']) { // eslint-disable-line dot-notation
return true;
}
diff --git a/src/lodash.fp.js b/src/lodash.fp.js
index b91c7d36b..b3cf7e922 100644
--- a/src/lodash.fp.js
+++ b/src/lodash.fp.js
@@ -1,5 +1,4 @@
-define(['lodash', 'lodash.converter', 'converse-core'], function (_, lodashConverter, converse) {
+define(['lodash', 'lodash.converter'], function (_, lodashConverter) {
var fp = lodashConverter(_.runInContext());
- converse.env.fp = fp;
return fp;
});
diff --git a/src/templates/spoiler_button.html b/src/templates/spoiler_button.html
index 591f82d7c..11f8fcf36 100644
--- a/src/templates/spoiler_button.html
+++ b/src/templates/spoiler_button.html
@@ -1,9 +1,6 @@
-{[ if (o.show_spoiler_button) { ]}
-
+ {[ if (o.composing_spoiler) { ]} icon-eye-blocked {[ } ]}
+ {[ if (!o.composing_spoiler) { ]} icon-eye {[ } ]}"
+ title="{{ o.label_toggle_spoiler }}">
-{[ } ]}
diff --git a/src/templates/toolbar.html b/src/templates/toolbar.html
index 13a10decd..0b6a7095e 100644
--- a/src/templates/toolbar.html
+++ b/src/templates/toolbar.html
@@ -4,14 +4,6 @@
{[ } ]}
-{[ if (o.show_spoiler_button) { ]}
-
-
-
-{[ } ]}
{[ if (o.show_call_button) { ]}
{[ } ]}