kaiwa/clientapp/pages/groupchat.js

416 lines
15 KiB
JavaScript
Raw Normal View History

2013-09-16 19:12:00 -04:00
/*global $, app, me, client*/
"use strict";
2013-12-13 19:16:40 -05:00
var _ = require('underscore');
2014-01-01 15:34:38 -05:00
var StayDown = require('staydown');
2013-09-16 19:12:00 -04:00
var BasePage = require('./base');
var templates = require('../templates');
2013-12-31 18:02:07 -05:00
var MUCRosterItem = require('../views/mucRosterItem');
2013-09-24 16:24:35 -04:00
var Message = require('../views/mucMessage');
2013-09-16 19:12:00 -04:00
var MessageModel = require('../models/message');
2014-01-01 19:24:11 -05:00
var embedIt = require('../helpers/embedIt');
2014-01-02 03:52:26 -05:00
var htmlify = require('../helpers/htmlify');
2014-11-17 15:09:54 -05:00
var tempSubject = '';
2013-09-16 19:12:00 -04:00
2014-01-01 15:34:38 -05:00
module.exports = BasePage.extend({
2013-09-16 19:12:00 -04:00
template: templates.pages.groupchat,
initialize: function (spec) {
this.editMode = false;
2013-12-13 19:16:40 -05:00
this.listenTo(this, 'pageloaded', this.handlePageLoaded);
this.listenTo(this, 'pageunloaded', this.handlePageUnloaded);
2013-12-18 16:31:22 -05:00
this.listenTo(this.model.messages, 'change', this.refreshModel);
2015-02-22 17:43:49 -05:00
this.listenTo(this.model.messages, 'reset', this.renderMessages);
this.listenTo(this.model, 'refresh', this.renderMessages);
app.state.bind('change:connected', this.connectionChange, this);
2013-12-13 19:16:40 -05:00
2013-09-16 19:12:00 -04:00
this.render();
},
events: {
'keydown textarea': 'handleKeyDown',
'keyup textarea': 'handleKeyUp',
2014-11-17 15:09:54 -05:00
'click .status': 'clickStatusChange',
'blur .status': 'blurStatusChange',
2015-02-09 10:20:28 -05:00
'keydown .status': 'keyDownStatusChange',
'click #members_toggle': 'clickMembersToggle'
2013-09-16 19:12:00 -04:00
},
2013-12-16 13:06:03 -05:00
classBindings: {
joined: '.controls'
},
2013-09-16 19:12:00 -04:00
textBindings: {
2013-12-20 02:04:14 -05:00
displayName: 'header .name',
2015-02-09 10:20:28 -05:00
subject: 'header .status',
membersCount: '#members_toggle_count'
2013-09-16 19:12:00 -04:00
},
show: function (animation) {
BasePage.prototype.show.apply(this, [animation]);
client.sendMessage({
type: 'groupchat',
2013-10-08 11:03:58 -04:00
to: this.model.jid,
2013-09-16 19:12:00 -04:00
chatState: 'active'
});
2015-02-08 18:21:00 -05:00
this.firstChanged = true;
var self = this;
$('.messages').scroll(function() {
if (self.firstChanged && $(".messages li:first-child").offset().top > 0) {
self.firstChanged = false;
self.model.fetchHistory();
}
});
2015-02-09 09:27:16 -05:00
this.$chatInput.focus();
2013-09-16 19:12:00 -04:00
},
hide: function () {
BasePage.prototype.hide.apply(this);
client.sendMessage({
type: 'groupchat',
2013-10-08 11:03:58 -04:00
to: this.model.jid,
2013-09-16 19:12:00 -04:00
chatState: 'inactive'
});
},
render: function () {
2013-12-13 19:16:40 -05:00
if (this.rendered) return this;
this.rendered = true;
2013-09-16 19:12:00 -04:00
this.renderAndBind();
this.$chatInput = this.$('.chatBox textarea');
2015-02-09 09:27:16 -05:00
this.$chatInput.val(app.composing[this.model.jid] || '');
2013-12-13 19:16:40 -05:00
this.$chatBox = this.$('.chatBox');
2013-09-16 19:12:00 -04:00
this.$messageList = this.$('.messages');
this.$autoComplete = this.$('.autoComplete');
2013-12-13 19:16:40 -05:00
2014-01-01 15:34:38 -05:00
this.staydown = new StayDown(this.$messageList[0], 500);
2013-12-13 19:16:40 -05:00
2013-12-31 18:02:07 -05:00
this.renderMessages();
2013-12-31 18:02:07 -05:00
this.renderCollection(this.model.resources, MUCRosterItem, this.$('.groupRoster'));
2013-12-13 19:16:40 -05:00
this.listenTo(this, 'rosterItemClicked', this.rosterItemSelected);
2014-01-01 15:34:38 -05:00
this.listenTo(this.model.messages, 'add', this.handleChatAdded);
2015-03-20 15:36:40 -04:00
this.listenTo(this.model.resources, 'add', this.handleResourceAdded);
2013-12-13 19:16:40 -05:00
2015-02-17 10:44:46 -05:00
$(window).on('resize', _.bind(this.resizeInput, this));
2013-12-13 19:16:40 -05:00
2013-09-16 19:12:00 -04:00
this.registerBindings();
2013-12-13 19:16:40 -05:00
2013-09-16 19:12:00 -04:00
return this;
},
2013-12-31 18:02:07 -05:00
renderMessages: function () {
2013-12-13 19:16:40 -05:00
var self = this;
2015-02-22 17:43:49 -05:00
this.$messageList.empty();
delete this.firstModel;
delete this.firstDate;
delete this.lastModel;
delete this.lastDate;
2013-12-13 19:16:40 -05:00
this.model.messages.each(function (model, i) {
self.appendModel(model);
});
2014-01-01 15:34:38 -05:00
this.staydown.checkdown();
2013-12-13 19:16:40 -05:00
},
handleChatAdded: function (model) {
this.appendModel(model, true);
},
2015-03-20 15:36:40 -04:00
handleResourceAdded: function (model) {
var xmppContact = me.getContact(model.id.split('/')[1]);
if (xmppContact) {
xmppContact.bind('change:avatar', this.handleAvatarChanged, this);
}
},
handleAvatarChanged: function(contact, uri) {
if (!me.isMe(contact.jid)) {
$('.' + contact.jid.substr(0, contact.jid.indexOf('@')) + ' .messageAvatar img').attr('src', uri);
}
},
2013-12-13 19:16:40 -05:00
handlePageLoaded: function () {
2014-01-01 15:34:38 -05:00
this.staydown.checkdown();
2015-02-17 10:44:46 -05:00
this.resizeInput();
2013-12-13 19:16:40 -05:00
},
2013-09-16 19:12:00 -04:00
handleKeyDown: function (e) {
2015-04-04 09:24:25 -04:00
if ((e.which === 13 || e.which === 9) && !e.shiftKey) { // Enter or Tab
if (this.$autoComplete.css('display') != 'none') {
var nickname = this.$autoComplete.find(">:nth-child(" + this.autoCompletePos + ")>:first-child").text();
this.rosterItemSelected(nickname);
} else {
app.composing[this.model.jid] = '';
this.sendChat();
}
2013-09-16 19:12:00 -04:00
e.preventDefault();
return false;
} else if (e.which === 38) { // Up arrow
if (this.$autoComplete.css('display') != 'none') {
var count = this.$autoComplete.find(">li").length;
var oldPos = this.autoCompletePos;
this.autoCompletePos = (oldPos - 1) < 1 ? count : oldPos - 1;
this.$autoComplete.find(">:nth-child(" + oldPos + ")").removeClass('selected');
this.$autoComplete.find(">:nth-child(" + this.autoCompletePos + ")").addClass('selected');
}
else if (this.$chatInput.val() === '' && this.model.lastSentMessage) {
this.editMode = true;
this.$chatInput.addClass('editing');
this.$chatInput.val(this.model.lastSentMessage.body);
}
2013-09-16 19:12:00 -04:00
e.preventDefault();
return false;
} else if (e.which === 40) { // Down arrow
if (this.$autoComplete.css('display') != 'none') {
var count = this.$autoComplete.find(">li").length;
var oldPos = this.autoCompletePos;
this.autoCompletePos = (oldPos + 1) > count ? 1 : oldPos + 1;
this.$autoComplete.find(">:nth-child(" + oldPos + ")").removeClass('selected');
this.$autoComplete.find(">:nth-child(" + this.autoCompletePos + ")").addClass('selected');
}
else if (this.editMode) {
this.editMode = false;
this.$chatInput.removeClass('editing');
}
2013-09-16 19:12:00 -04:00
e.preventDefault();
return false;
} else if (!e.ctrlKey && !e.metaKey) {
2013-12-18 17:01:32 -05:00
if (!this.typing || this.paused) {
2013-09-16 19:12:00 -04:00
this.typing = true;
2013-12-18 17:01:32 -05:00
this.paused = false;
2013-09-16 19:12:00 -04:00
client.sendMessage({
type: 'groupchat',
2013-10-08 11:03:58 -04:00
to: this.model.jid,
2013-09-16 19:12:00 -04:00
chatState: 'composing'
});
}
}
},
handleKeyUp: function (e) {
2015-02-17 10:44:46 -05:00
this.resizeInput();
2015-02-09 09:27:16 -05:00
app.composing[this.model.jid] = this.$chatInput.val();
2013-09-16 19:12:00 -04:00
if (this.typing && this.$chatInput.val().length === 0) {
this.typing = false;
2013-12-18 17:01:32 -05:00
this.paused = false;
2013-09-16 19:12:00 -04:00
client.sendMessage({
type: 'groupchat',
2013-10-08 11:03:58 -04:00
to: this.model.jid,
2013-09-16 19:12:00 -04:00
chatState: 'active'
});
2013-12-18 17:01:32 -05:00
} else if (this.typing) {
this.pausedTyping();
2013-09-16 19:12:00 -04:00
}
if (([38, 40, 13]).indexOf(e.which) === -1) {
var lastWord = this.$chatInput.val().split(' ').pop();
if (lastWord.charAt(0) === '@') {
var models = this.model.resources.search(lastWord.substr(1) || '', true, true);
if (models.length) {
this.renderCollection(models, MUCRosterItem, this.$autoComplete);
this.autoCompletePos = 1;
this.$autoComplete.find(">:nth-child(" + this.autoCompletePos + ")").addClass('selected');
this.$autoComplete.show();
}
else
this.$autoComplete.hide();
}
if (this.$autoComplete.css('display') != 'none') {
if( lastWord === '') {
this.$autoComplete.hide();
return;
}
}
}
},
rosterItemSelected: function (nickName) {
if (nickName == me.nick)
nickName = 'me';
var val = this.$chatInput.val();
var splited = val.split(' ');
var length = splited.length-1;
var lastWord = splited.pop();
if (('@' + nickName).indexOf(lastWord) > -1)
splited[length] = '@' + nickName + ' ';
else
splited.push('@' + nickName + ' ');
this.$chatInput.val(splited.join(' '));
this.$autoComplete.hide();
this.$chatInput.focus();
2013-09-16 19:12:00 -04:00
},
2014-01-01 15:34:38 -05:00
resizeInput: _.throttle(function () {
2013-09-16 19:12:00 -04:00
var height;
var scrollHeight;
2015-02-17 10:44:46 -05:00
var heightDiff;
2013-09-16 19:12:00 -04:00
var newHeight;
2015-02-17 10:44:46 -05:00
var newMargin;
var marginDelta;
var maxHeight = parseInt(this.$chatInput.css('max-height'), 10);
2013-09-16 19:12:00 -04:00
this.$chatInput.removeAttr('style');
2015-02-17 10:44:46 -05:00
height = this.$chatInput.outerHeight(),
2013-09-16 19:12:00 -04:00
scrollHeight = this.$chatInput.get(0).scrollHeight,
2015-02-17 10:44:46 -05:00
newHeight = Math.max(height, scrollHeight);
heightDiff = height - this.$chatInput.innerHeight();
2013-09-16 19:12:00 -04:00
if (newHeight > maxHeight) newHeight = maxHeight;
if (newHeight > height) {
2015-02-17 10:44:46 -05:00
this.$chatInput.css('height', newHeight+heightDiff);
this.$chatInput.scrollTop(this.$chatInput[0].scrollHeight - this.$chatInput.height());
newMargin = newHeight - height + heightDiff;
marginDelta = newMargin - parseInt(this.$messageList.css('marginBottom'), 10);
if (!!marginDelta) {
this.$messageList.css('marginBottom', newMargin);
2013-09-16 19:12:00 -04:00
}
2015-02-17 10:44:46 -05:00
} else {
this.$messageList.css('marginBottom', 0);
2013-09-16 19:12:00 -04:00
}
2014-01-01 15:34:38 -05:00
}, 300),
2013-12-18 17:01:32 -05:00
pausedTyping: _.debounce(function () {
if (this.typing && !this.paused) {
this.paused = true;
2013-09-16 19:12:00 -04:00
client.sendMessage({
type: 'groupchat',
2013-10-08 11:03:58 -04:00
to: this.model.jid,
2013-09-16 19:12:00 -04:00
chatState: 'paused'
});
}
2013-12-18 17:09:02 -05:00
}, 3000),
2013-09-16 19:12:00 -04:00
sendChat: function () {
var message;
var val = this.$chatInput.val();
if (val) {
2014-01-01 15:34:38 -05:00
this.staydown.intend_down = true;
2014-01-02 03:52:26 -05:00
var links = _.map(htmlify.collectLinks(val), function (link) {
return {url: link};
});
2013-09-16 19:12:00 -04:00
message = {
2013-09-24 16:24:35 -04:00
to: this.model.jid,
2013-09-16 19:12:00 -04:00
type: 'groupchat',
body: val,
2014-01-02 03:52:26 -05:00
chatState: 'active',
oobURIs: links
2013-09-16 19:12:00 -04:00
};
if (this.editMode) {
message.replace = this.model.lastSentMessage.mid || this.model.lastSentMessage.cid;
2013-09-16 19:12:00 -04:00
}
var id = client.sendMessage(message);
message.mid = id;
2013-12-13 19:16:40 -05:00
message.from = client.JID(this.model.jid.bare + '/' + this.model.nick);
2013-09-16 19:12:00 -04:00
if (this.editMode) {
this.model.lastSentMessage.correct(message);
} else {
var msgModel = new MessageModel(message);
2015-04-07 05:04:53 -04:00
this.model.addMessage(msgModel, false);
2013-09-16 19:12:00 -04:00
this.model.lastSentMessage = msgModel;
}
}
this.editMode = false;
this.typing = false;
2013-12-18 17:01:32 -05:00
this.paused = false;
2013-09-16 19:12:00 -04:00
this.$chatInput.removeClass('editing');
this.$chatInput.val('');
},
2014-11-17 15:09:54 -05:00
clickStatusChange: function (e) {
tempSubject = e.target.textContent;
},
blurStatusChange: function (e) {
var subject = e.target.textContent;
if (subject == '')
subject = true;
client.setSubject(this.model.jid, subject);
e.target.textContent = tempSubject;
},
keyDownStatusChange: function (e) {
if (e.which === 13 && !e.shiftKey) {
e.target.blur();
return false;
}
},
2015-02-09 10:20:28 -05:00
clickMembersToggle: function (e) {
var roster = $('.groupRoster');
if (roster.css('visibility') == 'hidden')
roster.css('visibility', 'visible');
else
roster.css('visibility', 'hidden');
},
2013-12-13 19:16:40 -05:00
appendModel: function (model, preload) {
var newEl, first, last;
2015-02-08 18:21:00 -05:00
var msgDate = Date.create(model.timestamp);
var messageDay = msgDate.format('{month} {ord}, {yyyy}');
if (this.firstModel === undefined || msgDate > Date.create(this.firstModel.timestamp)) {
if (this.firstModel === undefined) {
this.firstModel = model;
this.firstDate = messageDay;
}
if (messageDay !== this.lastDate) {
var dayDivider = $(templates.includes.dayDivider({day_name: messageDay}));
this.staydown.append(dayDivider[0]);
this.lastDate = messageDay;
}
2013-12-13 19:16:40 -05:00
2015-02-08 18:21:00 -05:00
var isGrouped = model.shouldGroupWith(this.lastModel);
if (isGrouped) {
newEl = $(model.partialTemplateHtml);
last = this.$messageList.find('li').last();
last.find('.messageWrapper').append(newEl);
last.addClass('chatGroup');
this.staydown.checkdown();
} else {
newEl = $(model.templateHtml);
2015-03-20 15:36:40 -04:00
newEl.addClass(model.sender.getNickname(model.from.full));
2015-02-08 18:21:00 -05:00
this.staydown.append(newEl[0]);
this.lastModel = model;
}
if (!model.pending) embedIt(newEl);
2015-02-09 10:20:28 -05:00
}
2015-02-08 18:21:00 -05:00
else {
var scrollDown = this.$messageList.prop('scrollHeight') - this.$messageList.scrollTop();
var firstEl = this.$messageList.find('li').first();
if (messageDay !== this.firstDate) {
var dayDivider = $(templates.includes.dayDivider({day_name: messageDay}));
firstEl.before(dayDivider[0]);
var firstEl = this.$messageList.find('li').first();
this.firstDate = messageDay;
}
var isGrouped = model.shouldGroupWith(this.firstModel);
if (isGrouped) {
newEl = $(model.partialTemplateHtml);
first = this.$messageList.find('li').first().next();
first.find('.messageWrapper div:first').after(newEl);
first.addClass('chatGroup');
} else {
newEl = $(model.templateHtml);
2015-03-20 15:36:40 -04:00
newEl.addClass(model.sender.getNickname(model.from.full));
2015-02-08 18:21:00 -05:00
firstEl.after(newEl[0]);
this.firstModel = model;
}
if (!model.pending) embedIt(newEl);
2015-02-09 10:20:28 -05:00
2015-02-08 18:21:00 -05:00
this.$messageList.scrollTop(this.$messageList.prop('scrollHeight') - scrollDown);
this.firstChanged = true;
2013-12-13 19:16:40 -05:00
}
},
refreshModel: function (model) {
var existing = this.$('#chat' + model.cid);
2015-04-07 07:12:20 -04:00
existing.replaceWith(model.bareMessageTemplate(existing.prev().hasClass('message_header')));
2014-01-01 20:42:36 -05:00
},
2015-02-22 17:43:49 -05:00
connectionChange: function () {
if (app.state.connected) {
this.$chatInput.attr("disabled", false);
} else {
this.$chatInput.attr("disabled", "disabled");
}
2013-09-16 19:12:00 -04:00
}
});