2013-08-29 23:38:28 -04:00
|
|
|
/*global $, app, me, client*/
|
|
|
|
"use strict";
|
|
|
|
|
2013-09-25 23:38:00 -04:00
|
|
|
var _ = require('underscore');
|
2014-01-01 15:34:38 -05:00
|
|
|
var StayDown = require('staydown');
|
2013-08-29 23:38:28 -04:00
|
|
|
var BasePage = require('./base');
|
|
|
|
var templates = require('../templates');
|
|
|
|
var Message = require('../views/message');
|
|
|
|
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');
|
2013-10-15 03:02:45 -04:00
|
|
|
var attachMediaStream = require('attachmediastream');
|
2013-08-29 23:38:28 -04:00
|
|
|
|
|
|
|
|
2014-01-01 15:34:38 -05:00
|
|
|
module.exports = BasePage.extend({
|
2013-08-29 23:38:28 -04:00
|
|
|
template: templates.pages.chat,
|
|
|
|
initialize: function (spec) {
|
|
|
|
this.editMode = false;
|
|
|
|
this.model.fetchHistory();
|
2013-09-25 23:38:00 -04: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);
|
2014-01-06 22:40:18 -05:00
|
|
|
this.listenTo(this.model.messages, 'sort', this.renderCollection);
|
2013-09-25 23:38:00 -04:00
|
|
|
|
2013-08-29 23:38:28 -04:00
|
|
|
this.render();
|
|
|
|
},
|
|
|
|
events: {
|
2013-09-16 05:19:07 -04:00
|
|
|
'keydown textarea': 'handleKeyDown',
|
2013-10-14 19:45:31 -04:00
|
|
|
'keyup textarea': 'handleKeyUp',
|
2013-10-16 02:00:56 -04:00
|
|
|
'click .call': 'handleCallClick',
|
|
|
|
'click .end': 'handleEndClick',
|
|
|
|
'click .mute': 'handleMuteClick'
|
2013-08-29 23:38:28 -04:00
|
|
|
},
|
|
|
|
srcBindings: {
|
2013-10-16 13:48:00 -04:00
|
|
|
avatar: 'header .avatar',
|
|
|
|
streamUrl: 'video.remote'
|
2013-08-29 23:38:28 -04:00
|
|
|
},
|
|
|
|
textBindings: {
|
2013-09-03 18:25:14 -04:00
|
|
|
displayName: 'header .name',
|
2013-12-20 02:04:14 -05:00
|
|
|
formattedTZO: 'header .tzo',
|
|
|
|
status: 'header .status'
|
2013-09-16 05:19:07 -04:00
|
|
|
},
|
2013-10-15 04:01:49 -04:00
|
|
|
classBindings: {
|
2013-12-20 02:04:14 -05:00
|
|
|
chatState: 'header',
|
|
|
|
idle: 'header',
|
|
|
|
show: 'header',
|
|
|
|
onCall: '.conversation'
|
2013-10-15 04:01:49 -04:00
|
|
|
},
|
2013-09-16 05:19:07 -04:00
|
|
|
show: function (animation) {
|
|
|
|
BasePage.prototype.show.apply(this, [animation]);
|
2014-01-05 03:52:45 -05:00
|
|
|
this.sendChatState('active');
|
2013-09-16 05:19:07 -04:00
|
|
|
},
|
|
|
|
hide: function () {
|
|
|
|
BasePage.prototype.hide.apply(this);
|
2014-01-05 03:52:45 -05:00
|
|
|
this.sendChatState('inactive');
|
2013-08-29 23:38:28 -04:00
|
|
|
},
|
|
|
|
render: function () {
|
2013-09-25 23:38:00 -04:00
|
|
|
if (this.rendered) return this;
|
2014-01-01 15:34:38 -05:00
|
|
|
var self = this;
|
|
|
|
|
2013-09-25 23:38:00 -04:00
|
|
|
this.rendered = true;
|
|
|
|
|
2013-08-29 23:38:28 -04:00
|
|
|
this.renderAndBind();
|
2013-09-25 23:38:00 -04:00
|
|
|
|
2013-09-16 05:19:07 -04:00
|
|
|
this.$chatInput = this.$('.chatBox textarea');
|
2013-09-25 23:38:00 -04:00
|
|
|
this.$chatBox = this.$('.chatBox');
|
2013-09-16 05:19:07 -04:00
|
|
|
this.$messageList = this.$('.messages');
|
2013-09-25 23:38:00 -04:00
|
|
|
|
2014-01-01 15:34:38 -05:00
|
|
|
this.staydown = new StayDown(this.$messageList[0], 500);
|
2013-09-25 23:38:00 -04:00
|
|
|
this.renderCollection();
|
|
|
|
|
2014-01-01 15:34:38 -05:00
|
|
|
this.listenTo(this.model.messages, 'add', this.handleChatAdded);
|
|
|
|
this.listenToAndRun(this.model, 'change:jingleResources', this.handleJingleResourcesChanged);
|
2013-09-25 23:38:00 -04:00
|
|
|
|
2014-01-01 15:34:38 -05:00
|
|
|
$(window).on('resize', _.bind(this.resizeInput, this));
|
2013-09-25 23:38:00 -04:00
|
|
|
|
2013-10-16 13:48:00 -04:00
|
|
|
this.registerBindings(me, {
|
|
|
|
srcBindings: {
|
|
|
|
streamUrl: 'video.local'
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2013-08-29 23:38:28 -04:00
|
|
|
return this;
|
|
|
|
},
|
2013-09-25 23:38:00 -04:00
|
|
|
handlePageLoaded: function () {
|
2014-01-01 15:34:38 -05:00
|
|
|
this.staydown.checkdown();
|
|
|
|
this.resizeInput();
|
2013-09-25 23:38:00 -04:00
|
|
|
},
|
2013-10-15 03:02:45 -04:00
|
|
|
handleCallClick: function (e) {
|
|
|
|
e.preventDefault();
|
2013-10-14 19:45:31 -04:00
|
|
|
this.model.call();
|
|
|
|
return false;
|
|
|
|
},
|
2013-09-25 23:38:00 -04:00
|
|
|
renderCollection: function () {
|
|
|
|
var self = this;
|
2014-01-06 22:40:18 -05:00
|
|
|
this.$messageList.empty();
|
2013-09-25 23:38:00 -04:00
|
|
|
this.model.messages.each(function (model, i) {
|
|
|
|
self.appendModel(model);
|
|
|
|
});
|
2014-01-01 15:34:38 -05:00
|
|
|
this.staydown.checkdown();
|
2013-09-25 23:38:00 -04:00
|
|
|
},
|
2013-08-29 23:38:28 -04:00
|
|
|
handleKeyDown: function (e) {
|
|
|
|
if (e.which === 13 && !e.shiftKey) {
|
|
|
|
this.sendChat();
|
|
|
|
e.preventDefault();
|
|
|
|
return false;
|
2013-09-15 18:06:37 -04:00
|
|
|
} else if (e.which === 38 && this.$chatInput.val() === '' && this.model.lastSentMessage) {
|
2013-08-29 23:38:28 -04:00
|
|
|
this.editMode = true;
|
2013-09-15 18:06:37 -04:00
|
|
|
this.$chatInput.addClass('editing');
|
|
|
|
this.$chatInput.val(this.model.lastSentMessage.body);
|
2013-08-29 23:38:28 -04:00
|
|
|
e.preventDefault();
|
|
|
|
return false;
|
|
|
|
} else if (e.which === 40 && this.editMode) {
|
|
|
|
this.editMode = false;
|
2013-09-15 18:06:37 -04:00
|
|
|
this.$chatInput.removeClass('editing');
|
2013-08-29 23:38:28 -04:00
|
|
|
e.preventDefault();
|
|
|
|
return false;
|
2013-10-12 00:20:18 -04:00
|
|
|
} else if (!e.ctrlKey && !e.metaKey) {
|
2013-12-18 17:01:32 -05:00
|
|
|
if (!this.typing || this.paused) {
|
2013-09-09 19:00:13 -04:00
|
|
|
this.typing = true;
|
2013-12-18 17:01:32 -05:00
|
|
|
this.paused = false;
|
2013-12-20 06:39:06 -05:00
|
|
|
this.$chatInput.addClass('typing');
|
2014-01-05 03:52:45 -05:00
|
|
|
this.sendChatState('composing');
|
2013-09-09 19:00:13 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
|
|
|
handleKeyUp: function (e) {
|
2013-09-15 18:06:37 -04:00
|
|
|
this.resizeInput();
|
|
|
|
if (this.typing && this.$chatInput.val().length === 0) {
|
2013-09-09 19:00:13 -04:00
|
|
|
this.typing = false;
|
2013-12-20 06:39:06 -05:00
|
|
|
this.$chatInput.removeClass('typing');
|
2014-01-05 03:52:45 -05:00
|
|
|
this.sendChatState('active');
|
2013-12-18 17:01:32 -05:00
|
|
|
} else if (this.typing) {
|
|
|
|
this.pausedTyping();
|
2013-09-09 19:00:13 -04:00
|
|
|
}
|
|
|
|
},
|
2013-12-18 17:01:32 -05:00
|
|
|
pausedTyping: _.debounce(function () {
|
|
|
|
if (this.typing && !this.paused) {
|
|
|
|
this.paused = true;
|
2014-01-05 03:52:45 -05:00
|
|
|
this.sendChatState('paused');
|
2013-08-29 23:38:28 -04:00
|
|
|
}
|
2013-12-18 17:09:02 -05:00
|
|
|
}, 3000),
|
2014-01-05 03:52:45 -05:00
|
|
|
sendChatState: function (state) {
|
|
|
|
if (!this.model.supportsChatStates) return;
|
|
|
|
client.sendMessage({
|
|
|
|
to: this.model.lockedResource || this.model.jid,
|
|
|
|
chatState: state
|
|
|
|
});
|
|
|
|
},
|
2013-08-29 23:38:28 -04:00
|
|
|
sendChat: function () {
|
|
|
|
var message;
|
2013-09-15 18:06:37 -04:00
|
|
|
var val = this.$chatInput.val();
|
2013-08-29 23:38:28 -04:00
|
|
|
|
|
|
|
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-08-29 23:38:28 -04:00
|
|
|
message = {
|
2014-01-05 07:19:46 -05:00
|
|
|
to: client.JID(this.model.lockedResource || this.model.jid),
|
2013-08-29 23:38:28 -04:00
|
|
|
type: 'chat',
|
|
|
|
body: val,
|
2014-01-05 03:52:45 -05:00
|
|
|
requestReceipt: true,
|
2014-01-02 03:52:26 -05:00
|
|
|
oobURIs: links
|
2013-08-29 23:38:28 -04:00
|
|
|
};
|
2014-01-05 03:52:45 -05:00
|
|
|
if (this.model.supportsChatStates) {
|
|
|
|
message.chatState = 'active';
|
|
|
|
}
|
2013-08-29 23:38:28 -04:00
|
|
|
if (this.editMode) {
|
2013-09-25 23:38:00 -04:00
|
|
|
message.replace = this.model.lastSentMessage.id;
|
2013-08-29 23:38:28 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
var id = client.sendMessage(message);
|
2013-12-18 13:06:54 -05:00
|
|
|
message.mid = id;
|
2013-08-29 23:38:28 -04:00
|
|
|
message.from = me.jid;
|
|
|
|
|
|
|
|
if (this.editMode) {
|
|
|
|
this.model.lastSentMessage.correct(message);
|
|
|
|
} else {
|
|
|
|
var msgModel = new MessageModel(message);
|
2013-12-18 16:31:22 -05:00
|
|
|
this.model.addMessage(msgModel);
|
2013-08-29 23:38:28 -04:00
|
|
|
this.model.lastSentMessage = msgModel;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
this.editMode = false;
|
2013-09-09 19:00:13 -04:00
|
|
|
this.typing = false;
|
2013-12-18 17:01:32 -05:00
|
|
|
this.paused = false;
|
2013-12-20 06:39:06 -05:00
|
|
|
this.$chatInput.removeClass('typing');
|
2013-09-15 18:06:37 -04:00
|
|
|
this.$chatInput.removeClass('editing');
|
|
|
|
this.$chatInput.val('');
|
2013-09-25 23:38:00 -04:00
|
|
|
},
|
|
|
|
handleChatAdded: function (model) {
|
|
|
|
this.appendModel(model, true);
|
|
|
|
},
|
|
|
|
refreshModel: function (model) {
|
|
|
|
var existing = this.$('#chat' + model.cid);
|
|
|
|
existing.replaceWith(model.partialTemplateHtml);
|
|
|
|
},
|
2013-10-14 19:45:31 -04:00
|
|
|
handleJingleResourcesChanged: function (model, val) {
|
|
|
|
var resources = val || this.model.jingleResources;
|
|
|
|
this.$('button.call').prop('disabled', !resources.length);
|
|
|
|
},
|
2013-09-25 23:38:00 -04:00
|
|
|
appendModel: function (model, preload) {
|
|
|
|
var self = this;
|
|
|
|
var isGrouped = model.shouldGroupWith(this.lastModel);
|
|
|
|
var newEl, first, last;
|
|
|
|
|
|
|
|
if (isGrouped) {
|
|
|
|
newEl = $(model.partialTemplateHtml);
|
|
|
|
last = this.$messageList.find('li').last();
|
|
|
|
last.find('.messageWrapper').append(newEl);
|
|
|
|
last.addClass('chatGroup');
|
2014-01-01 19:24:11 -05:00
|
|
|
this.staydown.checkdown();
|
2013-09-25 23:38:00 -04:00
|
|
|
} else {
|
|
|
|
newEl = $(model.templateHtml);
|
2014-01-01 15:34:38 -05:00
|
|
|
this.staydown.append(newEl[0]);
|
2013-09-25 23:38:00 -04:00
|
|
|
}
|
2014-01-01 19:24:11 -05:00
|
|
|
embedIt(newEl);
|
2013-09-25 23:38:00 -04:00
|
|
|
this.lastModel = model;
|
2013-10-16 02:00:56 -04:00
|
|
|
},
|
|
|
|
handleEndClick: function (e) {
|
|
|
|
e.preventDefault();
|
|
|
|
this.model.jingleCall.end({
|
|
|
|
condition: 'success'
|
|
|
|
});
|
|
|
|
return false;
|
|
|
|
},
|
|
|
|
handleMuteClick: function (e) {
|
|
|
|
return false;
|
2014-01-01 15:34:38 -05:00
|
|
|
},
|
|
|
|
resizeInput: _.throttle(function () {
|
|
|
|
var height;
|
|
|
|
var scrollHeight;
|
|
|
|
var newHeight;
|
|
|
|
var newPadding;
|
|
|
|
var paddingDelta;
|
|
|
|
var maxHeight = 102;
|
|
|
|
|
|
|
|
this.$chatInput.removeAttr('style');
|
|
|
|
height = this.$chatInput.height() + 10;
|
|
|
|
scrollHeight = this.$chatInput.get(0).scrollHeight;
|
|
|
|
newHeight = scrollHeight + 2;
|
|
|
|
|
|
|
|
if (newHeight > maxHeight) newHeight = maxHeight;
|
|
|
|
if (newHeight > height) {
|
|
|
|
this.$chatInput.css('height', newHeight);
|
|
|
|
newPadding = newHeight + 21;
|
|
|
|
paddingDelta = newPadding - parseInt(this.$messageList.css('paddingBottom'), 10);
|
|
|
|
if (!!paddingDelta) {
|
|
|
|
this.$messageList.css('paddingBottom', newPadding);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}, 300)
|
2013-08-29 23:38:28 -04:00
|
|
|
});
|