Merge remote-tracking branch 'origin/master'
This commit is contained in:
commit
ae502a53c2
@ -827,7 +827,7 @@
|
|||||||
test_utils.openChatBoxFor(_converse, sender_jid);
|
test_utils.openChatBoxFor(_converse, sender_jid);
|
||||||
|
|
||||||
var chatboxview = _converse.chatboxviews.get(sender_jid);
|
var chatboxview = _converse.chatboxviews.get(sender_jid);
|
||||||
spyOn(chatboxview, 'scrollDown').and.callThrough();
|
spyOn(chatboxview, 'onScrolledDown').and.callThrough();
|
||||||
|
|
||||||
// Create enough messages so that there's a scrollbar.
|
// Create enough messages so that there's a scrollbar.
|
||||||
var message = 'This message is received while the chat area is scrolled up';
|
var message = 'This message is received while the chat area is scrolled up';
|
||||||
@ -841,13 +841,13 @@
|
|||||||
.c('active', {'xmlns': 'http://jabber.org/protocol/chatstates'}).tree());
|
.c('active', {'xmlns': 'http://jabber.org/protocol/chatstates'}).tree());
|
||||||
}
|
}
|
||||||
return test_utils.waitUntil(function () {
|
return test_utils.waitUntil(function () {
|
||||||
return chatboxview.$content.scrollTop();
|
return chatboxview.content.scrollTop;
|
||||||
}, 1000).then(function () {
|
}, 1000).then(function () {
|
||||||
return test_utils.waitUntil(function () {
|
return test_utils.waitUntil(function () {
|
||||||
return !chatboxview.model.get('auto_scrolled');
|
return !chatboxview.model.get('auto_scrolled');
|
||||||
}, 500);
|
}, 500);
|
||||||
}).then(function () {
|
}).then(function () {
|
||||||
chatboxview.$content.scrollTop(0);
|
chatboxview.content.scrollTop = 0;
|
||||||
return test_utils.waitUntil(function () {
|
return test_utils.waitUntil(function () {
|
||||||
return chatboxview.model.get('scrolled');
|
return chatboxview.model.get('scrolled');
|
||||||
}, 900);
|
}, 900);
|
||||||
@ -869,10 +869,10 @@
|
|||||||
}, 500);
|
}, 500);
|
||||||
}).then(function () {
|
}).then(function () {
|
||||||
expect(chatboxview.model.get('scrolled')).toBe(true);
|
expect(chatboxview.model.get('scrolled')).toBe(true);
|
||||||
expect(chatboxview.$content.scrollTop()).toBe(0);
|
expect(chatboxview.content.scrollTop).toBe(0);
|
||||||
expect(chatboxview.$('.new-msgs-indicator').is(':visible')).toBeTruthy();
|
expect(chatboxview.$('.new-msgs-indicator').is(':visible')).toBeTruthy();
|
||||||
// Scroll down again
|
// Scroll down again
|
||||||
chatboxview.$content.scrollTop(chatboxview.$content[0].scrollHeight);
|
chatboxview.content.scrollTop = chatboxview.content.scrollHeight;
|
||||||
return test_utils.waitUntil(function () {
|
return test_utils.waitUntil(function () {
|
||||||
return !chatboxview.$('.new-msgs-indicator').is(':visible');
|
return !chatboxview.$('.new-msgs-indicator').is(':visible');
|
||||||
}, 700);
|
}, 700);
|
||||||
|
@ -1356,7 +1356,7 @@
|
|||||||
}
|
}
|
||||||
// Give enough time for `markScrolled` to have been called
|
// Give enough time for `markScrolled` to have been called
|
||||||
setTimeout(function () {
|
setTimeout(function () {
|
||||||
view.$content.scrollTop(0);
|
view.content.scrollTop = 0;
|
||||||
view.handleMUCMessage(
|
view.handleMUCMessage(
|
||||||
$msg({
|
$msg({
|
||||||
from: 'lounge@localhost/someone',
|
from: 'lounge@localhost/someone',
|
||||||
@ -1369,7 +1369,7 @@
|
|||||||
var $chat_content = view.$el.find('.chat-content');
|
var $chat_content = view.$el.find('.chat-content');
|
||||||
var msg_txt = $chat_content.find('.chat-message:last').find('.chat-msg-content').text();
|
var msg_txt = $chat_content.find('.chat-message:last').find('.chat-msg-content').text();
|
||||||
expect(msg_txt).toEqual(message);
|
expect(msg_txt).toEqual(message);
|
||||||
expect(view.$content.scrollTop()).toBe(0);
|
expect(view.content.scrollTop).toBe(0);
|
||||||
done();
|
done();
|
||||||
}, 500);
|
}, 500);
|
||||||
});
|
});
|
||||||
|
@ -8,7 +8,6 @@
|
|||||||
|
|
||||||
(function (root, factory) {
|
(function (root, factory) {
|
||||||
define([
|
define([
|
||||||
"jquery.noconflict",
|
|
||||||
"converse-core",
|
"converse-core",
|
||||||
"converse-chatboxes",
|
"converse-chatboxes",
|
||||||
"emojione",
|
"emojione",
|
||||||
@ -25,7 +24,6 @@
|
|||||||
"tpl!toolbar"
|
"tpl!toolbar"
|
||||||
], factory);
|
], factory);
|
||||||
}(this, function (
|
}(this, function (
|
||||||
$,
|
|
||||||
converse,
|
converse,
|
||||||
dummy,
|
dummy,
|
||||||
emojione,
|
emojione,
|
||||||
@ -265,6 +263,7 @@
|
|||||||
},
|
},
|
||||||
|
|
||||||
initialize () {
|
initialize () {
|
||||||
|
this.scrollDown = _.debounce(this._scrollDown, 250);
|
||||||
this.markScrolled = _.debounce(this._markScrolled, 100);
|
this.markScrolled = _.debounce(this._markScrolled, 100);
|
||||||
this.createEmojiPicker();
|
this.createEmojiPicker();
|
||||||
this.model.messages.on('add', this.onMessageAdded, this);
|
this.model.messages.on('add', this.onMessageAdded, this);
|
||||||
@ -295,7 +294,6 @@
|
|||||||
}
|
}
|
||||||
));
|
));
|
||||||
this.content = this.el.querySelector('.chat-content');
|
this.content = this.el.querySelector('.chat-content');
|
||||||
this.$content = $(this.content);
|
|
||||||
return this;
|
return this;
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -348,7 +346,7 @@
|
|||||||
},
|
},
|
||||||
|
|
||||||
clearStatusNotification () {
|
clearStatusNotification () {
|
||||||
u.removeElement(this.content.querySelector('div.chat-event'));
|
u.removeElement(this.content.querySelector('.chat-event'));
|
||||||
},
|
},
|
||||||
|
|
||||||
showStatusNotification (message, keep_old, permanent) {
|
showStatusNotification (message, keep_old, permanent) {
|
||||||
@ -409,9 +407,9 @@
|
|||||||
* Parameters:
|
* Parameters:
|
||||||
* (Object) attrs: An object containing the message attributes.
|
* (Object) attrs: An object containing the message attributes.
|
||||||
*/
|
*/
|
||||||
_.flow(($el) => {
|
_.flow((el) => {
|
||||||
insert_method($el[0]);
|
insert_method(el);
|
||||||
return $el;
|
return el;
|
||||||
},
|
},
|
||||||
this.scrollDown.bind(this)
|
this.scrollDown.bind(this)
|
||||||
)(this.renderMessage(attrs));
|
)(this.renderMessage(attrs));
|
||||||
@ -564,7 +562,7 @@
|
|||||||
template = tpl_message;
|
template = tpl_message;
|
||||||
username = attrs.sender === 'me' && __('me') || fullname;
|
username = attrs.sender === 'me' && __('me') || fullname;
|
||||||
}
|
}
|
||||||
$(this.content).find('div.chat-event').remove();
|
this.clearStatusNotification();
|
||||||
|
|
||||||
if (text.length > 8000) {
|
if (text.length > 8000) {
|
||||||
text = text.substring(0, 10) + '...';
|
text = text.substring(0, 10) + '...';
|
||||||
@ -575,7 +573,7 @@
|
|||||||
true, true);
|
true, true);
|
||||||
}
|
}
|
||||||
const msg_time = moment(attrs.time) || moment;
|
const msg_time = moment(attrs.time) || moment;
|
||||||
const $msg = $(template(
|
const msg = u.stringToElement(template(
|
||||||
_.extend(this.getExtraMessageTemplateAttributes(attrs), {
|
_.extend(this.getExtraMessageTemplateAttributes(attrs), {
|
||||||
'msgid': attrs.msgid,
|
'msgid': attrs.msgid,
|
||||||
'sender': attrs.sender,
|
'sender': attrs.sender,
|
||||||
@ -585,12 +583,12 @@
|
|||||||
'extra_classes': this.getExtraMessageClasses(attrs)
|
'extra_classes': this.getExtraMessageClasses(attrs)
|
||||||
})
|
})
|
||||||
));
|
));
|
||||||
const msg_content = $msg[0].querySelector('.chat-msg-content');
|
const msg_content = msg.querySelector('.chat-msg-content');
|
||||||
msg_content.innerHTML = u.addEmoji(
|
msg_content.innerHTML = u.addEmoji(
|
||||||
_converse, emojione, u.addHyperlinks(xss.filterXSS(text, {'whiteList': {}}))
|
_converse, emojione, u.addHyperlinks(xss.filterXSS(text, {'whiteList': {}}))
|
||||||
);
|
);
|
||||||
u.renderImageURLs(msg_content);
|
u.renderImageURLs(msg_content);
|
||||||
return $msg;
|
return msg;
|
||||||
},
|
},
|
||||||
|
|
||||||
showHelpMessages (msgs, type, spinner) {
|
showHelpMessages (msgs, type, spinner) {
|
||||||
@ -604,7 +602,7 @@
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
if (spinner === true) {
|
if (spinner === true) {
|
||||||
$(this.content).append(tpl_spinner);
|
this.addSpinner();
|
||||||
} else if (spinner === false) {
|
} else if (spinner === false) {
|
||||||
this.clearSpinner();
|
this.clearSpinner();
|
||||||
}
|
}
|
||||||
@ -629,14 +627,14 @@
|
|||||||
this.showStatusNotification(message.get('fullname')+' '+__('has stopped typing'));
|
this.showStatusNotification(message.get('fullname')+' '+__('has stopped typing'));
|
||||||
}
|
}
|
||||||
} else if (_.includes([_converse.INACTIVE, _converse.ACTIVE], message.get('chat_state'))) {
|
} else if (_.includes([_converse.INACTIVE, _converse.ACTIVE], message.get('chat_state'))) {
|
||||||
$(this.content).find('div.chat-event').remove();
|
this.clearStatusNotification();
|
||||||
} else if (message.get('chat_state') === _converse.GONE) {
|
} else if (message.get('chat_state') === _converse.GONE) {
|
||||||
this.showStatusNotification(message.get('fullname')+' '+__('has gone away'));
|
this.showStatusNotification(message.get('fullname')+' '+__('has gone away'));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
shouldShowOnTextMessage () {
|
shouldShowOnTextMessage () {
|
||||||
return !this.$el.is(':visible');
|
return !u.isVisible(this.el);
|
||||||
},
|
},
|
||||||
|
|
||||||
handleTextMessage (message) {
|
handleTextMessage (message) {
|
||||||
@ -854,12 +852,13 @@
|
|||||||
},
|
},
|
||||||
|
|
||||||
insertIntoTextArea (value) {
|
insertIntoTextArea (value) {
|
||||||
const $textbox = this.$el.find('textarea.chat-textarea');
|
const textbox_el = this.el.querySelector('.chat-textarea');
|
||||||
let existing = $textbox.val();
|
let existing = textbox_el.value;
|
||||||
if (existing && (existing[existing.length-1] !== ' ')) {
|
if (existing && (existing[existing.length-1] !== ' ')) {
|
||||||
existing = existing + ' ';
|
existing = existing + ' ';
|
||||||
}
|
}
|
||||||
$textbox.focus().val(existing+value+' ');
|
textbox_el.value = existing+value+' ';
|
||||||
|
textbox_el.focus()
|
||||||
},
|
},
|
||||||
|
|
||||||
insertEmoji (ev) {
|
insertEmoji (ev) {
|
||||||
@ -900,7 +899,7 @@
|
|||||||
const chat_status = item.get('chat_status');
|
const chat_status = item.get('chat_status');
|
||||||
let fullname = item.get('fullname');
|
let fullname = item.get('fullname');
|
||||||
fullname = _.isEmpty(fullname)? item.get('jid'): fullname;
|
fullname = _.isEmpty(fullname)? item.get('jid'): fullname;
|
||||||
if (this.$el.is(':visible')) {
|
if (u.isVisible(this.el)) {
|
||||||
if (chat_status === 'offline') {
|
if (chat_status === 'offline') {
|
||||||
this.showStatusNotification(fullname+' '+__('has gone offline'));
|
this.showStatusNotification(fullname+' '+__('has gone offline'));
|
||||||
} else if (chat_status === 'away') {
|
} else if (chat_status === 'away') {
|
||||||
@ -908,7 +907,7 @@
|
|||||||
} else if ((chat_status === 'dnd')) {
|
} else if ((chat_status === 'dnd')) {
|
||||||
this.showStatusNotification(fullname+' '+__('is busy'));
|
this.showStatusNotification(fullname+' '+__('is busy'));
|
||||||
} else if (chat_status === 'online') {
|
} else if (chat_status === 'online') {
|
||||||
this.$el.find('div.chat-event').remove();
|
this.clearStatusNotification();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -1043,8 +1042,8 @@
|
|||||||
}
|
}
|
||||||
let scrolled = true;
|
let scrolled = true;
|
||||||
const is_at_bottom =
|
const is_at_bottom =
|
||||||
($(this.content).scrollTop() + $(this.content).innerHeight()) >=
|
(this.content.scrollTop + this.content.clientHeight) >=
|
||||||
$(this.content)[0].scrollHeight-10;
|
this.content.scrollHeight - 62; // sigh...
|
||||||
|
|
||||||
if (is_at_bottom) {
|
if (is_at_bottom) {
|
||||||
scrolled = false;
|
scrolled = false;
|
||||||
@ -1070,18 +1069,6 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
scrollDown () {
|
|
||||||
if (_.isUndefined(this.debouncedScrollDown)) {
|
|
||||||
/* We wrap the method in a debouncer and set it on the
|
|
||||||
* instance, so that we have it debounced per instance.
|
|
||||||
* Debouncing it on the class-level is too broad.
|
|
||||||
*/
|
|
||||||
this.debouncedScrollDown = _.debounce(this._scrollDown, 250);
|
|
||||||
}
|
|
||||||
this.debouncedScrollDown.apply(this, arguments);
|
|
||||||
return this;
|
|
||||||
},
|
|
||||||
|
|
||||||
onScrolledDown() {
|
onScrolledDown() {
|
||||||
this.hideNewMessagesIndicator();
|
this.hideNewMessagesIndicator();
|
||||||
if (_converse.windowState !== 'hidden') {
|
if (_converse.windowState !== 'hidden') {
|
||||||
|
@ -82,6 +82,7 @@
|
|||||||
},
|
},
|
||||||
|
|
||||||
initialize () {
|
initialize () {
|
||||||
|
this.scrollDown = _.debounce(this._scrollDown, 250);
|
||||||
this.markScrolled = _.debounce(this._markScrolled, 100);
|
this.markScrolled = _.debounce(this._markScrolled, 100);
|
||||||
this.disable_mam = true; // Don't do MAM queries for this box
|
this.disable_mam = true; // Don't do MAM queries for this box
|
||||||
this.model.messages.on('add', this.onMessageAdded, this);
|
this.model.messages.on('add', this.onMessageAdded, this);
|
||||||
@ -106,8 +107,7 @@
|
|||||||
unread_msgs: ''
|
unread_msgs: ''
|
||||||
}
|
}
|
||||||
));
|
));
|
||||||
this.$content = this.$el.find('.chat-content');
|
this.content = this.el.querySelector('.chat-content');
|
||||||
this.content = this.$content[0];
|
|
||||||
utils.refreshWebkit();
|
utils.refreshWebkit();
|
||||||
return this;
|
return this;
|
||||||
},
|
},
|
||||||
|
@ -36,7 +36,7 @@
|
|||||||
//
|
//
|
||||||
// New functions which don't exist yet can also be added.
|
// New functions which don't exist yet can also be added.
|
||||||
ChatBox: {
|
ChatBox: {
|
||||||
getMessageAttributes ($message, $delay, original_stanza) {
|
getMessageAttributes (message, delay, original_stanza) {
|
||||||
const attrs = this.__super__.getMessageAttributes.apply(this, arguments);
|
const attrs = this.__super__.getMessageAttributes.apply(this, arguments);
|
||||||
const result = sizzle(`stanza-id[xmlns="${Strophe.NS.SID}"]`, original_stanza).pop();
|
const result = sizzle(`stanza-id[xmlns="${Strophe.NS.SID}"]`, original_stanza).pop();
|
||||||
if (!_.isUndefined(result)) {
|
if (!_.isUndefined(result)) {
|
||||||
@ -50,7 +50,7 @@
|
|||||||
render () {
|
render () {
|
||||||
const result = this.__super__.render.apply(this, arguments);
|
const result = this.__super__.render.apply(this, arguments);
|
||||||
if (!this.disable_mam) {
|
if (!this.disable_mam) {
|
||||||
this.$content.on('scroll', _.debounce(this.onScroll.bind(this), 100));
|
this.content.addEventListener('scroll', _.debounce(this.onScroll.bind(this), 100));
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
},
|
},
|
||||||
@ -194,7 +194,7 @@
|
|||||||
renderChatArea () {
|
renderChatArea () {
|
||||||
const result = this.__super__.renderChatArea.apply(this, arguments);
|
const result = this.__super__.renderChatArea.apply(this, arguments);
|
||||||
if (!this.disable_mam) {
|
if (!this.disable_mam) {
|
||||||
this.$content.on('scroll', _.debounce(this.onScroll.bind(this), 100));
|
this.content.addEventListener('scroll', _.debounce(this.onScroll.bind(this), 100));
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
},
|
},
|
||||||
|
@ -158,9 +158,9 @@
|
|||||||
if (ev && ev.preventDefault) { ev.preventDefault(); }
|
if (ev && ev.preventDefault) { ev.preventDefault(); }
|
||||||
// save the scroll position to restore it on maximize
|
// save the scroll position to restore it on maximize
|
||||||
if (this.model.collection && this.model.collection.browserStorage) {
|
if (this.model.collection && this.model.collection.browserStorage) {
|
||||||
this.model.save({'scroll': this.$content.scrollTop()});
|
this.model.save({'scroll': this.content.scrollTop});
|
||||||
} else {
|
} else {
|
||||||
this.model.set({'scroll': this.$content.scrollTop()});
|
this.model.set({'scroll': this.content.scrollTop});
|
||||||
}
|
}
|
||||||
this.setChatState(_converse.INACTIVE).model.minimize();
|
this.setChatState(_converse.INACTIVE).model.minimize();
|
||||||
this.hide();
|
this.hide();
|
||||||
|
@ -11,7 +11,6 @@
|
|||||||
*/
|
*/
|
||||||
(function (root, factory) {
|
(function (root, factory) {
|
||||||
define([
|
define([
|
||||||
"jquery.noconflict",
|
|
||||||
"form-utils",
|
"form-utils",
|
||||||
"converse-core",
|
"converse-core",
|
||||||
"lodash.fp",
|
"lodash.fp",
|
||||||
@ -42,7 +41,6 @@
|
|||||||
"backbone.vdomview"
|
"backbone.vdomview"
|
||||||
], factory);
|
], factory);
|
||||||
}(this, function (
|
}(this, function (
|
||||||
$,
|
|
||||||
u,
|
u,
|
||||||
converse,
|
converse,
|
||||||
fp,
|
fp,
|
||||||
@ -439,6 +437,7 @@
|
|||||||
},
|
},
|
||||||
|
|
||||||
initialize () {
|
initialize () {
|
||||||
|
this.scrollDown = _.debounce(this._scrollDown, 250);
|
||||||
this.markScrolled = _.debounce(this._markScrolled, 100);
|
this.markScrolled = _.debounce(this._markScrolled, 100);
|
||||||
|
|
||||||
this.model.messages.on('add', this.onMessageAdded, this);
|
this.model.messages.on('add', this.onMessageAdded, this);
|
||||||
@ -501,7 +500,6 @@
|
|||||||
container_el.insertAdjacentElement('beforeend', this.occupantsview.el);
|
container_el.insertAdjacentElement('beforeend', this.occupantsview.el);
|
||||||
this.renderToolbar(tpl_chatroom_toolbar);
|
this.renderToolbar(tpl_chatroom_toolbar);
|
||||||
this.content = this.el.querySelector('.chat-content');
|
this.content = this.el.querySelector('.chat-content');
|
||||||
this.$content = $(this.content);
|
|
||||||
this.toggleOccupants(null, true);
|
this.toggleOccupants(null, true);
|
||||||
}
|
}
|
||||||
return this;
|
return this;
|
||||||
|
@ -63,12 +63,12 @@
|
|||||||
} else {
|
} else {
|
||||||
value = field.value;
|
value = field.value;
|
||||||
}
|
}
|
||||||
return u.stringToDOM(
|
return u.stringToNode(
|
||||||
tpl_field({
|
tpl_field({
|
||||||
name: field.getAttribute('name'),
|
name: field.getAttribute('name'),
|
||||||
value: value
|
value: value
|
||||||
})
|
})
|
||||||
)[0];
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
u.xForm2webForm = function (field, stanza, domain) {
|
u.xForm2webForm = function (field, stanza, domain) {
|
||||||
|
21
src/utils.js
21
src/utils.js
@ -402,15 +402,30 @@
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
u.stringToDOM = function (s) {
|
u.stringToNode = function (s) {
|
||||||
/* Converts an HTML string into a DOM element.
|
/* Converts an HTML string into a DOM Node.
|
||||||
|
* Expects that the HTML string has only one top-level element,
|
||||||
|
* i.e. not multiple ones.
|
||||||
*
|
*
|
||||||
* Parameters:
|
* Parameters:
|
||||||
* (String) s - The HTML string
|
* (String) s - The HTML string
|
||||||
*/
|
*/
|
||||||
var div = document.createElement('div');
|
var div = document.createElement('div');
|
||||||
div.innerHTML = s;
|
div.innerHTML = s;
|
||||||
return div.childNodes;
|
return div.firstChild;
|
||||||
|
};
|
||||||
|
|
||||||
|
u.stringToElement = function (s) {
|
||||||
|
/* Converts an HTML string into a DOM element.
|
||||||
|
* Expects that the HTML string has only one top-level element,
|
||||||
|
* i.e. not multiple ones.
|
||||||
|
*
|
||||||
|
* Parameters:
|
||||||
|
* (String) s - The HTML string
|
||||||
|
*/
|
||||||
|
var div = document.createElement('div');
|
||||||
|
div.innerHTML = s;
|
||||||
|
return div.firstElementChild;
|
||||||
};
|
};
|
||||||
|
|
||||||
u.matchesSelector = function (el, selector) {
|
u.matchesSelector = function (el, selector) {
|
||||||
|
Loading…
Reference in New Issue
Block a user