您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

Chat.js 11KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368
  1. /* global APP, $ */
  2. import {processReplacements, linkify} from './Replacement';
  3. import CommandsProcessor from './Commands';
  4. import ToolbarToggler from '../../toolbars/ToolbarToggler';
  5. import VideoLayout from "../../videolayout/VideoLayout";
  6. import UIUtil from '../../util/UIUtil';
  7. import UIEvents from '../../../../service/UI/UIEvents';
  8. import { smileys } from './smileys';
  9. let unreadMessages = 0;
  10. const sidePanelsContainerId = 'sideToolbarContainer';
  11. const htmlStr = `
  12. <div id="chat_container" class="sideToolbarContainer__inner">
  13. <div id="nickname">
  14. <span data-i18n="chat.nickname.title"></span>
  15. <form>
  16. <input type='text'
  17. class="input-control" id="nickinput" autofocus
  18. data-i18n="[placeholder]chat.nickname.popover">
  19. </form>
  20. </div>
  21. <div id="chatconversation"></div>
  22. <audio id="chatNotification" src="sounds/incomingMessage.wav"
  23. preload="auto"></audio>
  24. <textarea id="usermsg" autofocus
  25. data-i18n="[placeholder]chat.messagebox"></textarea>
  26. <div id="smileysarea">
  27. <div id="smileys" id="toggle_smileys">
  28. <img src="images/smile.svg"/>
  29. </div>
  30. </div>
  31. </div>`;
  32. function initHTML() {
  33. $(`#${sidePanelsContainerId}`)
  34. .append(htmlStr);
  35. }
  36. /**
  37. * The container id, which is and the element id.
  38. */
  39. var CHAT_CONTAINER_ID = "chat_container";
  40. /**
  41. * Updates visual notification, indicating that a message has arrived.
  42. */
  43. function updateVisualNotification() {
  44. var unreadMsgElement = document.getElementById('unreadMessages');
  45. if (unreadMessages) {
  46. unreadMsgElement.innerHTML = unreadMessages.toString();
  47. ToolbarToggler.dockToolbar(true);
  48. var chatButtonElement
  49. = document.getElementById('toolbar_button_chat');
  50. var leftIndent = (UIUtil.getTextWidth(chatButtonElement) -
  51. UIUtil.getTextWidth(unreadMsgElement)) / 2;
  52. var topIndent = (UIUtil.getTextHeight(chatButtonElement) -
  53. UIUtil.getTextHeight(unreadMsgElement)) / 2 - 5;
  54. unreadMsgElement.setAttribute(
  55. 'style',
  56. 'top:' + topIndent +
  57. '; left:' + leftIndent + ';');
  58. }
  59. else {
  60. unreadMsgElement.innerHTML = '';
  61. }
  62. $(unreadMsgElement).parent()[unreadMessages > 0 ? 'show' : 'hide']();
  63. }
  64. /**
  65. * Returns the current time in the format it is shown to the user
  66. * @returns {string}
  67. */
  68. function getCurrentTime(stamp) {
  69. var now = (stamp? new Date(stamp): new Date());
  70. var hour = now.getHours();
  71. var minute = now.getMinutes();
  72. var second = now.getSeconds();
  73. if(hour.toString().length === 1) {
  74. hour = '0'+hour;
  75. }
  76. if(minute.toString().length === 1) {
  77. minute = '0'+minute;
  78. }
  79. if(second.toString().length === 1) {
  80. second = '0'+second;
  81. }
  82. return hour+':'+minute+':'+second;
  83. }
  84. function toggleSmileys() {
  85. var smileys = $('#smileysContainer');
  86. if(!smileys.is(':visible')) {
  87. smileys.show("slide", { direction: "down", duration: 300});
  88. } else {
  89. smileys.hide("slide", { direction: "down", duration: 300});
  90. }
  91. $('#usermsg').focus();
  92. }
  93. function addClickFunction(smiley, number) {
  94. smiley.onclick = function addSmileyToMessage() {
  95. var usermsg = $('#usermsg');
  96. var message = usermsg.val();
  97. message += smileys['smiley' + number];
  98. usermsg.val(message);
  99. usermsg.get(0).setSelectionRange(message.length, message.length);
  100. toggleSmileys();
  101. usermsg.focus();
  102. };
  103. }
  104. /**
  105. * Adds the smileys container to the chat
  106. */
  107. function addSmileys() {
  108. var smileysContainer = document.createElement('div');
  109. smileysContainer.id = 'smileysContainer';
  110. for(var i = 1; i <= 21; i++) {
  111. var smileyContainer = document.createElement('div');
  112. smileyContainer.id = 'smiley' + i;
  113. smileyContainer.className = 'smileyContainer';
  114. var smiley = document.createElement('img');
  115. smiley.src = 'images/smileys/smiley' + i + '.svg';
  116. smiley.className = 'smiley';
  117. addClickFunction(smiley, i);
  118. smileyContainer.appendChild(smiley);
  119. smileysContainer.appendChild(smileyContainer);
  120. }
  121. $("#chat_container").append(smileysContainer);
  122. }
  123. /**
  124. * Resizes the chat conversation.
  125. */
  126. function resizeChatConversation() {
  127. var msgareaHeight = $('#usermsg').outerHeight();
  128. var chatspace = $('#' + CHAT_CONTAINER_ID);
  129. var width = chatspace.width();
  130. var chat = $('#chatconversation');
  131. var smileys = $('#smileysarea');
  132. smileys.height(msgareaHeight);
  133. $("#smileys").css('bottom', (msgareaHeight - 26) / 2);
  134. $('#smileysContainer').css('bottom', msgareaHeight);
  135. chat.width(width - 10);
  136. chat.height(window.innerHeight - 15 - msgareaHeight);
  137. }
  138. /**
  139. * Focus input after 400 ms
  140. * Found input by id
  141. *
  142. * @param id {string} input id
  143. */
  144. function deferredFocus(id){
  145. setTimeout(() => $(`#${id}`).focus(), 400);
  146. }
  147. /**
  148. * Chat related user interface.
  149. */
  150. var Chat = {
  151. /**
  152. * Initializes chat related interface.
  153. */
  154. init (eventEmitter) {
  155. initHTML();
  156. if (APP.settings.getDisplayName()) {
  157. Chat.setChatConversationMode(true);
  158. }
  159. $("#toggle_smileys").click(function() {
  160. Chat.toggleSmileys();
  161. });
  162. $('#nickinput').keydown(function (event) {
  163. if (event.keyCode === 13) {
  164. event.preventDefault();
  165. let val = this.value;
  166. this.value = '';
  167. eventEmitter.emit(UIEvents.NICKNAME_CHANGED, val);
  168. deferredFocus('usermsg');
  169. }
  170. });
  171. var usermsg = $('#usermsg');
  172. usermsg.keydown(function (event) {
  173. if (event.keyCode === 13) {
  174. event.preventDefault();
  175. var value = this.value;
  176. usermsg.val('').trigger('autosize.resize');
  177. this.focus();
  178. var command = new CommandsProcessor(value, eventEmitter);
  179. if (command.isCommand()) {
  180. command.processCommand();
  181. } else {
  182. var message = UIUtil.escapeHtml(value);
  183. eventEmitter.emit(UIEvents.MESSAGE_CREATED, message);
  184. }
  185. }
  186. });
  187. var onTextAreaResize = function () {
  188. resizeChatConversation();
  189. Chat.scrollChatToBottom();
  190. };
  191. usermsg.autosize({callback: onTextAreaResize});
  192. eventEmitter.on(UIEvents.SIDE_TOOLBAR_CONTAINER_TOGGLED,
  193. function(containerId, isVisible) {
  194. if (containerId !== CHAT_CONTAINER_ID || !isVisible)
  195. return;
  196. unreadMessages = 0;
  197. updateVisualNotification();
  198. // Undock the toolbar when the chat is shown and if we're in a
  199. // video mode.
  200. if (VideoLayout.isLargeVideoVisible()) {
  201. ToolbarToggler.dockToolbar(false);
  202. }
  203. // if we are in conversation mode focus on the text input
  204. // if we are not, focus on the display name input
  205. if (APP.settings.getDisplayName())
  206. deferredFocus('usermsg');
  207. else
  208. deferredFocus('nickinput');
  209. });
  210. addSmileys();
  211. updateVisualNotification();
  212. },
  213. /**
  214. * Appends the given message to the chat conversation.
  215. */
  216. updateChatConversation (id, displayName, message, stamp) {
  217. var divClassName = '';
  218. if (APP.conference.isLocalId(id)) {
  219. divClassName = "localuser";
  220. } else {
  221. divClassName = "remoteuser";
  222. if (!Chat.isVisible()) {
  223. unreadMessages++;
  224. UIUtil.playSoundNotification('chatNotification');
  225. updateVisualNotification();
  226. }
  227. }
  228. // replace links and smileys
  229. // Strophe already escapes special symbols on sending,
  230. // so we escape here only tags to avoid double &amp;
  231. var escMessage = message.replace(/</g, '&lt;').
  232. replace(/>/g, '&gt;').replace(/\n/g, '<br/>');
  233. var escDisplayName = UIUtil.escapeHtml(displayName);
  234. message = processReplacements(escMessage);
  235. var messageContainer =
  236. '<div class="chatmessage">'+
  237. '<img src="images/chatArrow.svg" class="chatArrow">' +
  238. '<div class="username ' + divClassName +'">' + escDisplayName +
  239. '</div>' + '<div class="timestamp">' + getCurrentTime(stamp) +
  240. '</div>' + '<div class="usermessage">' + message + '</div>' +
  241. '</div>';
  242. $('#chatconversation').append(messageContainer);
  243. $('#chatconversation').animate(
  244. { scrollTop: $('#chatconversation')[0].scrollHeight}, 1000);
  245. },
  246. /**
  247. * Appends error message to the conversation
  248. * @param errorMessage the received error message.
  249. * @param originalText the original message.
  250. */
  251. chatAddError (errorMessage, originalText) {
  252. errorMessage = UIUtil.escapeHtml(errorMessage);
  253. originalText = UIUtil.escapeHtml(originalText);
  254. $('#chatconversation').append(
  255. '<div class="errorMessage"><b>Error: </b>' + 'Your message' +
  256. (originalText? (' \"'+ originalText + '\"') : "") +
  257. ' was not sent.' +
  258. (errorMessage? (' Reason: ' + errorMessage) : '') + '</div>');
  259. $('#chatconversation').animate(
  260. { scrollTop: $('#chatconversation')[0].scrollHeight}, 1000);
  261. },
  262. /**
  263. * Sets the subject to the UI
  264. * @param subject the subject
  265. */
  266. setSubject (subject) {
  267. if (subject) {
  268. subject = subject.trim();
  269. }
  270. let subjectId = 'subject';
  271. let html = linkify(UIUtil.escapeHtml(subject));
  272. $(`#${subjectId}`).html(html);
  273. UIUtil.setVisible(subjectId, subject && subject.length > 0);
  274. },
  275. /**
  276. * Sets the chat conversation mode.
  277. * Conversation mode is the normal chat mode, non conversation mode is
  278. * where we ask user to input its display name.
  279. * @param {boolean} isConversationMode if chat should be in
  280. * conversation mode or not.
  281. */
  282. setChatConversationMode (isConversationMode) {
  283. $('#' + CHAT_CONTAINER_ID)
  284. .toggleClass('is-conversation-mode', isConversationMode);
  285. },
  286. /**
  287. * Resizes the chat area.
  288. */
  289. resizeChat (width, height) {
  290. $('#' + CHAT_CONTAINER_ID).width(width).height(height);
  291. resizeChatConversation();
  292. },
  293. /**
  294. * Indicates if the chat is currently visible.
  295. */
  296. isVisible () {
  297. return UIUtil.isVisible(
  298. document.getElementById(CHAT_CONTAINER_ID));
  299. },
  300. /**
  301. * Shows and hides the window with the smileys
  302. */
  303. toggleSmileys,
  304. /**
  305. * Scrolls chat to the bottom.
  306. */
  307. scrollChatToBottom () {
  308. setTimeout(
  309. () => {
  310. const chatconversation = $('#chatconversation');
  311. // XXX Prevent TypeError: undefined is not an object when the
  312. // Web browser does not support WebRTC (yet).
  313. chatconversation.length > 0
  314. && chatconversation.scrollTop(
  315. chatconversation[0].scrollHeight);
  316. },
  317. 5);
  318. }
  319. };
  320. export default Chat;