You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

chat.js 16KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452
  1. /* global $, Util, connection, nickname:true, getVideoSize, getVideoPosition, showToolbar, processReplacements */
  2. /**
  3. * Chat related user interface.
  4. */
  5. var Chat = (function (my) {
  6. var notificationInterval = false;
  7. var unreadMessages = 0;
  8. /**
  9. * Initializes chat related interface.
  10. */
  11. my.init = function () {
  12. var storedDisplayName = window.localStorage.displayname;
  13. if (storedDisplayName) {
  14. nickname = storedDisplayName;
  15. Chat.setChatConversationMode(true);
  16. }
  17. $('#nickinput').keydown(function (event) {
  18. if (event.keyCode === 13) {
  19. event.preventDefault();
  20. var val = Util.escapeHtml(this.value);
  21. this.value = '';
  22. if (!nickname) {
  23. nickname = val;
  24. window.localStorage.displayname = nickname;
  25. connection.emuc.addDisplayNameToPresence(nickname);
  26. connection.emuc.sendPresence();
  27. Chat.setChatConversationMode(true);
  28. return;
  29. }
  30. }
  31. });
  32. $('#usermsg').keydown(function (event) {
  33. if (event.keyCode === 13) {
  34. event.preventDefault();
  35. var value = this.value;
  36. $('#usermsg').val('').trigger('autosize.resize');
  37. this.focus();
  38. var command = new CommandsProcessor(value);
  39. if(command.isCommand())
  40. {
  41. command.processCommand();
  42. }
  43. else
  44. {
  45. var message = Util.escapeHtml(value);
  46. connection.emuc.sendMessage(message, nickname);
  47. }
  48. }
  49. });
  50. var onTextAreaResize = function () {
  51. resizeChatConversation();
  52. scrollChatToBottom();
  53. };
  54. $('#usermsg').autosize({callback: onTextAreaResize});
  55. $("#chatspace").bind("shown",
  56. function () {
  57. unreadMessages = 0;
  58. setVisualNotification(false);
  59. });
  60. addSmileys();
  61. };
  62. /**
  63. * Appends the given message to the chat conversation.
  64. */
  65. my.updateChatConversation = function (from, displayName, message) {
  66. var divClassName = '';
  67. if (connection.emuc.myroomjid === from) {
  68. divClassName = "localuser";
  69. }
  70. else {
  71. divClassName = "remoteuser";
  72. if (!Chat.isVisible()) {
  73. unreadMessages++;
  74. Util.playSoundNotification('chatNotification');
  75. setVisualNotification(true);
  76. }
  77. }
  78. //replace links and smileys
  79. var escMessage = Util.escapeHtml(message);
  80. var escDisplayName = Util.escapeHtml(displayName);
  81. message = processReplacements(escMessage);
  82. var messageContainer =
  83. '<div class="chatmessage">'+
  84. '<img src="../images/chatArrow.svg" class="chatArrow">' +
  85. '<div class="username ' + divClassName +'">' + escDisplayName + '</div>' +
  86. '<div class="timestamp">' + getCurrentTime() + '</div>' +
  87. '<div class="usermessage">' + message + '</div>' +
  88. '</div>';
  89. $('#chatconversation').append(messageContainer);
  90. $('#chatconversation').animate(
  91. { scrollTop: $('#chatconversation')[0].scrollHeight}, 1000);
  92. };
  93. /**
  94. * Appends error message to the conversation
  95. * @param errorMessage the received error message.
  96. * @param originalText the original message.
  97. */
  98. my.chatAddError = function(errorMessage, originalText)
  99. {
  100. errorMessage = Util.escapeHtml(errorMessage);
  101. originalText = Util.escapeHtml(originalText);
  102. $('#chatconversation').append('<div class="errorMessage"><b>Error: </b>'
  103. + 'Your message' + (originalText? (' \"'+ originalText + '\"') : "")
  104. + ' was not sent.' + (errorMessage? (' Reason: ' + errorMessage) : '')
  105. + '</div>');
  106. $('#chatconversation').animate(
  107. { scrollTop: $('#chatconversation')[0].scrollHeight}, 1000);
  108. };
  109. /**
  110. * Sets the subject to the UI
  111. * @param subject the subject
  112. */
  113. my.chatSetSubject = function(subject)
  114. {
  115. if(subject)
  116. subject = subject.trim();
  117. $('#subject').html(linkify(Util.escapeHtml(subject)));
  118. if(subject == "")
  119. {
  120. $("#subject").css({display: "none"});
  121. }
  122. else
  123. {
  124. $("#subject").css({display: "block"});
  125. }
  126. };
  127. /**
  128. * Opens / closes the chat area.
  129. */
  130. my.toggleChat = function () {
  131. var chatspace = $('#chatspace');
  132. var videospace = $('#videospace');
  133. var chatSize = (Chat.isVisible()) ? [0, 0] : Chat.getChatSize();
  134. var videospaceWidth = window.innerWidth - chatSize[0];
  135. var videospaceHeight = window.innerHeight;
  136. var videoSize
  137. = getVideoSize(null, null, videospaceWidth, videospaceHeight);
  138. var videoWidth = videoSize[0];
  139. var videoHeight = videoSize[1];
  140. var videoPosition = getVideoPosition(videoWidth,
  141. videoHeight,
  142. videospaceWidth,
  143. videospaceHeight);
  144. var horizontalIndent = videoPosition[0];
  145. var verticalIndent = videoPosition[1];
  146. var thumbnailSize = VideoLayout.calculateThumbnailSize(videospaceWidth);
  147. var thumbnailsWidth = thumbnailSize[0];
  148. var thumbnailsHeight = thumbnailSize[1];
  149. var completeFunction = Chat.isVisible() ?
  150. function() {} : function () {
  151. scrollChatToBottom();
  152. chatspace.trigger('shown');
  153. };
  154. videospace.animate({right: chatSize[0],
  155. width: videospaceWidth,
  156. height: videospaceHeight},
  157. {queue: false,
  158. duration: 500,
  159. complete: completeFunction});
  160. $('#remoteVideos').animate({height: thumbnailsHeight},
  161. {queue: false,
  162. duration: 500});
  163. $('#remoteVideos>span').animate({height: thumbnailsHeight,
  164. width: thumbnailsWidth},
  165. {queue: false,
  166. duration: 500,
  167. complete: function() {
  168. $(document).trigger(
  169. "remotevideo.resized",
  170. [thumbnailsWidth,
  171. thumbnailsHeight]);
  172. }});
  173. $('#largeVideoContainer').animate({ width: videospaceWidth,
  174. height: videospaceHeight},
  175. {queue: false,
  176. duration: 500
  177. });
  178. $('#largeVideo').animate({ width: videoWidth,
  179. height: videoHeight,
  180. top: verticalIndent,
  181. bottom: verticalIndent,
  182. left: horizontalIndent,
  183. right: horizontalIndent},
  184. { queue: false,
  185. duration: 500
  186. }
  187. );
  188. if (Chat.isVisible()) {
  189. chatspace.hide("slide", { direction: "right",
  190. queue: false,
  191. duration: 500});
  192. }
  193. else {
  194. // Undock the toolbar when the chat is shown and if we're in a
  195. // video mode.
  196. if (VideoLayout.isLargeVideoVisible()) {
  197. ToolbarToggler.dockToolbar(false);
  198. }
  199. chatspace.show("slide", { direction: "right",
  200. queue: false,
  201. duration: 500,
  202. complete: function () {
  203. // Request the focus in the nickname field or the chat input field.
  204. if ($('#nickname').css('visibility') === 'visible') {
  205. $('#nickinput').focus();
  206. } else {
  207. $('#usermsg').focus();
  208. }
  209. }
  210. });
  211. Chat.resizeChat();
  212. }
  213. };
  214. /**
  215. * Sets the chat conversation mode.
  216. */
  217. my.setChatConversationMode = function (isConversationMode) {
  218. if (isConversationMode) {
  219. $('#nickname').css({visibility: 'hidden'});
  220. $('#chatconversation').css({visibility: 'visible'});
  221. $('#usermsg').css({visibility: 'visible'});
  222. $('#smileysarea').css({visibility: 'visible'});
  223. $('#usermsg').focus();
  224. }
  225. };
  226. /**
  227. * Resizes the chat area.
  228. */
  229. my.resizeChat = function () {
  230. var chatSize = Chat.getChatSize();
  231. $('#chatspace').width(chatSize[0]);
  232. $('#chatspace').height(chatSize[1]);
  233. resizeChatConversation();
  234. };
  235. /**
  236. * Returns the size of the chat.
  237. */
  238. my.getChatSize = function () {
  239. var availableHeight = window.innerHeight;
  240. var availableWidth = window.innerWidth;
  241. var chatWidth = 200;
  242. if (availableWidth * 0.2 < 200)
  243. chatWidth = availableWidth * 0.2;
  244. return [chatWidth, availableHeight];
  245. };
  246. /**
  247. * Indicates if the chat is currently visible.
  248. */
  249. my.isVisible = function () {
  250. return $('#chatspace').is(":visible");
  251. };
  252. /**
  253. * Shows and hides the window with the smileys
  254. */
  255. my.toggleSmileys = function() {
  256. var smileys = $('#smileysContainer');
  257. if(!smileys.is(':visible')) {
  258. smileys.show("slide", { direction: "down", duration: 300});
  259. } else {
  260. smileys.hide("slide", { direction: "down", duration: 300});
  261. }
  262. $('#usermsg').focus();
  263. };
  264. /**
  265. * Adds the smileys container to the chat
  266. */
  267. function addSmileys() {
  268. var smileysContainer = document.createElement('div');
  269. smileysContainer.id = 'smileysContainer';
  270. function addClickFunction(smiley, number) {
  271. smiley.onclick = function addSmileyToMessage() {
  272. var usermsg = $('#usermsg');
  273. var message = usermsg.val();
  274. message += smileys['smiley' + number];
  275. usermsg.val(message);
  276. usermsg.get(0).setSelectionRange(message.length, message.length);
  277. Chat.toggleSmileys();
  278. usermsg.focus();
  279. };
  280. }
  281. for(var i = 1; i <= 21; i++) {
  282. var smileyContainer = document.createElement('div');
  283. smileyContainer.id = 'smiley' + i;
  284. smileyContainer.className = 'smileyContainer';
  285. var smiley = document.createElement('img');
  286. smiley.src = 'images/smileys/smiley' + i + '.svg';
  287. smiley.className = 'smiley';
  288. addClickFunction(smiley, i);
  289. smileyContainer.appendChild(smiley);
  290. smileysContainer.appendChild(smileyContainer);
  291. }
  292. $("#chatspace").append(smileysContainer);
  293. }
  294. /**
  295. * Resizes the chat conversation.
  296. */
  297. function resizeChatConversation() {
  298. var msgareaHeight = $('#usermsg').outerHeight();
  299. var chatspace = $('#chatspace');
  300. var width = chatspace.width();
  301. var chat = $('#chatconversation');
  302. var smileys = $('#smileysarea');
  303. smileys.height(msgareaHeight);
  304. $("#smileys").css('bottom', (msgareaHeight - 26) / 2);
  305. $('#smileysContainer').css('bottom', msgareaHeight);
  306. chat.width(width - 10);
  307. chat.height(window.innerHeight - 15 - msgareaHeight);
  308. }
  309. /**
  310. * Shows/hides a visual notification, indicating that a message has arrived.
  311. */
  312. function setVisualNotification(show) {
  313. var unreadMsgElement = document.getElementById('unreadMessages');
  314. var unreadMsgBottomElement = document.getElementById('bottomUnreadMessages');
  315. var glower = $('#chatButton');
  316. var bottomGlower = $('#chatBottomButton');
  317. if (unreadMessages) {
  318. unreadMsgElement.innerHTML = unreadMessages.toString();
  319. unreadMsgBottomElement.innerHTML = unreadMessages.toString();
  320. ToolbarToggler.dockToolbar(true);
  321. var chatButtonElement
  322. = document.getElementById('chatButton').parentNode;
  323. var leftIndent = (Util.getTextWidth(chatButtonElement) -
  324. Util.getTextWidth(unreadMsgElement)) / 2;
  325. var topIndent = (Util.getTextHeight(chatButtonElement) -
  326. Util.getTextHeight(unreadMsgElement)) / 2 - 3;
  327. unreadMsgElement.setAttribute(
  328. 'style',
  329. 'top:' + topIndent +
  330. '; left:' + leftIndent + ';');
  331. var chatBottomButtonElement
  332. = document.getElementById('chatBottomButton').parentNode;
  333. var bottomLeftIndent = (Util.getTextWidth(chatBottomButtonElement) -
  334. Util.getTextWidth(unreadMsgBottomElement)) / 2;
  335. var bottomTopIndent = (Util.getTextHeight(chatBottomButtonElement) -
  336. Util.getTextHeight(unreadMsgBottomElement)) / 2 - 2;
  337. unreadMsgBottomElement.setAttribute(
  338. 'style',
  339. 'top:' + bottomTopIndent +
  340. '; left:' + bottomLeftIndent + ';');
  341. if (!glower.hasClass('icon-chat-simple')) {
  342. glower.removeClass('icon-chat');
  343. glower.addClass('icon-chat-simple');
  344. }
  345. }
  346. else {
  347. unreadMsgElement.innerHTML = '';
  348. unreadMsgBottomElement.innerHTML = '';
  349. glower.removeClass('icon-chat-simple');
  350. glower.addClass('icon-chat');
  351. }
  352. if (show && !notificationInterval) {
  353. notificationInterval = window.setInterval(function () {
  354. glower.toggleClass('active');
  355. bottomGlower.toggleClass('active glowing');
  356. }, 800);
  357. }
  358. else if (!show && notificationInterval) {
  359. window.clearInterval(notificationInterval);
  360. notificationInterval = false;
  361. glower.removeClass('active');
  362. bottomGlower.removeClass('glowing');
  363. bottomGlower.addClass('active');
  364. }
  365. }
  366. /**
  367. * Scrolls chat to the bottom.
  368. */
  369. function scrollChatToBottom() {
  370. setTimeout(function () {
  371. $('#chatconversation').scrollTop(
  372. $('#chatconversation')[0].scrollHeight);
  373. }, 5);
  374. }
  375. /**
  376. * Returns the current time in the format it is shown to the user
  377. * @returns {string}
  378. */
  379. function getCurrentTime() {
  380. var now = new Date();
  381. var hour = now.getHours();
  382. var minute = now.getMinutes();
  383. var second = now.getSeconds();
  384. if(hour.toString().length === 1) {
  385. hour = '0'+hour;
  386. }
  387. if(minute.toString().length === 1) {
  388. minute = '0'+minute;
  389. }
  390. if(second.toString().length === 1) {
  391. second = '0'+second;
  392. }
  393. return hour+':'+minute+':'+second;
  394. }
  395. return my;
  396. }(Chat || {}));