Source: jsxc.lib.xmpp.chatState.js

  1. /**
  2. * Implements XEP-0085: Chat State Notifications.
  3. *
  4. * @namespace jsxc.xmpp.chatState
  5. * @see {@link http://xmpp.org/extensions/xep-0085.html}
  6. */
  7. jsxc.xmpp.chatState = {
  8. conn: null,
  9. /** Delay between two notification on the message composing */
  10. toComposingNotificationDelay: 900,
  11. };
  12. jsxc.xmpp.chatState.init = function() {
  13. var self = jsxc.xmpp.chatState;
  14. if (!jsxc.xmpp.conn || !jsxc.xmpp.connected) {
  15. $(document).on('attached.jsxc', self.init);
  16. return;
  17. }
  18. // prevent double execution after reconnect
  19. $(document).off('composing.chatstates', jsxc.xmpp.chatState.onComposing);
  20. $(document).off('paused.chatstates', jsxc.xmpp.chatState.onPaused);
  21. $(document).off('active.chatstates', jsxc.xmpp.chatState.onActive);
  22. if (self.isDisabled()) {
  23. jsxc.debug('chat state notification disabled');
  24. return;
  25. }
  26. self.conn = jsxc.xmpp.conn;
  27. $(document).on('composing.chatstates', jsxc.xmpp.chatState.onComposing);
  28. $(document).on('paused.chatstates', jsxc.xmpp.chatState.onPaused);
  29. $(document).on('active.chatstates', jsxc.xmpp.chatState.onActive);
  30. };
  31. /**
  32. * Composing event received. Display message.
  33. *
  34. * @memberOf jsxc.xmpp.chatState
  35. * @param {Event} ev
  36. * @param {String} jid
  37. */
  38. jsxc.xmpp.chatState.onComposing = function(ev, jid) {
  39. var self = jsxc.xmpp.chatState;
  40. var bid = jsxc.jidToBid(jid);
  41. var data = jsxc.storage.getUserItem('buddy', bid) || null;
  42. if (!data || jsxc.xmpp.chatState.isDisabled()) {
  43. return;
  44. }
  45. // ignore own notifications in groupchat
  46. if (data.type === 'groupchat' &&
  47. Strophe.getResourceFromJid(jid) === Strophe.getNodeFromJid(self.conn.jid)) {
  48. return;
  49. }
  50. var user = data.type === 'groupchat' ? Strophe.getResourceFromJid(jid) : data.name;
  51. var win = jsxc.gui.window.get(bid);
  52. if (win.length === 0) {
  53. return;
  54. }
  55. // add user in array if necessary
  56. var usersComposing = win.data('composing') || [];
  57. if (usersComposing.indexOf(user) === -1) {
  58. usersComposing.push(user);
  59. win.data('composing', usersComposing);
  60. }
  61. var msg = self._genComposingMsg(data.type, usersComposing);
  62. jsxc.xmpp.chatState.setStatus(win, msg);
  63. };
  64. /**
  65. * Pause event receive. Remove or update composing message.
  66. *
  67. * @memberOf jsxc.xmpp.chatState
  68. * @param {Event} ev
  69. * @param {String} jid
  70. */
  71. jsxc.xmpp.chatState.onPaused = function(ev, jid) {
  72. var self = jsxc.xmpp.chatState;
  73. var bid = jsxc.jidToBid(jid);
  74. var data = jsxc.storage.getUserItem('buddy', bid) || null;
  75. if (!data || jsxc.xmpp.chatState.isDisabled()) {
  76. return;
  77. }
  78. var user = data.type === 'groupchat' ? Strophe.getResourceFromJid(jid) : data.name;
  79. var win = jsxc.gui.window.get(bid);
  80. if (win.length === 0) {
  81. return;
  82. }
  83. var usersComposing = win.data('composing') || [];
  84. if (usersComposing.indexOf(user) >= 0) {
  85. // remove user from list
  86. usersComposing.splice(usersComposing.indexOf(user), 1);
  87. win.data('composing', usersComposing);
  88. }
  89. var composingMsg;
  90. if (usersComposing.length !== 0) {
  91. composingMsg = self._genComposingMsg(data.type, usersComposing);
  92. }
  93. jsxc.xmpp.chatState.setStatus(win, composingMsg);
  94. };
  95. /**
  96. * Active event received.
  97. *
  98. * @memberOf jsxc.xmpp.chatState
  99. * @param {Event} ev
  100. * @param {String} jid
  101. */
  102. jsxc.xmpp.chatState.onActive = function(ev, jid) {
  103. jsxc.xmpp.chatState.onPaused(ev, jid);
  104. };
  105. /**
  106. * Send composing event.
  107. *
  108. * @memberOf jsxc.xmpp.chatState
  109. * @param {String} bid
  110. */
  111. jsxc.xmpp.chatState.startComposing = function(bid) {
  112. var self = jsxc.xmpp.chatState;
  113. if (!jsxc.xmpp.conn || !jsxc.xmpp.conn.chatstates || jsxc.xmpp.chatState.isDisabled()) {
  114. return;
  115. }
  116. var win = jsxc.gui.window.get(bid);
  117. var timeout = win.data('composing-timeout');
  118. var type = win.hasClass('jsxc_groupchat') ? 'groupchat' : 'chat';
  119. if (timeout) {
  120. // @REVIEW page reload?
  121. clearTimeout(timeout);
  122. } else {
  123. jsxc.xmpp.conn.chatstates.sendComposing(bid, type);
  124. }
  125. timeout = setTimeout(function() {
  126. self.pauseComposing(bid, type);
  127. win.data('composing-timeout', null);
  128. }, self.toComposingNotificationDelay);
  129. win.data('composing-timeout', timeout);
  130. };
  131. /**
  132. * Send pause event.
  133. *
  134. * @memberOf jsxc.xmpp.chatState
  135. * @param {String} bid
  136. */
  137. jsxc.xmpp.chatState.pauseComposing = function(bid, type) {
  138. if (jsxc.xmpp.chatState.isDisabled()) {
  139. return;
  140. }
  141. jsxc.xmpp.conn.chatstates.sendPaused(bid, type);
  142. };
  143. /**
  144. * End composing without sending a pause event.
  145. *
  146. * @memberOf jsxc.xmpp.chatState
  147. * @param {String} bid
  148. */
  149. jsxc.xmpp.chatState.endComposing = function(bid) {
  150. var win = jsxc.gui.window.get(bid);
  151. if (win.data('composing-timeout')) {
  152. clearTimeout(win.data('composing-timeout'));
  153. }
  154. };
  155. /**
  156. * Generate composing message.
  157. *
  158. * @memberOf jsxc.xmpp.chatState
  159. * @param {String} the type of the chat ('groupchat' or 'chat')
  160. * @param {Array} usersComposing List of users which are currently composing a message
  161. */
  162. jsxc.xmpp.chatState._genComposingMsg = function(chatType, usersComposing) {
  163. if (!usersComposing || usersComposing.length === 0) {
  164. jsxc.debug('usersComposing array is empty?');
  165. return '';
  166. } else {
  167. if (chatType === 'groupchat') {
  168. return usersComposing.length > 1 ? usersComposing.join(', ') + $.t('_are_composing') :
  169. usersComposing[0] + $.t('_is_composing');
  170. }
  171. return $.t('_is_composing');
  172. }
  173. };
  174. jsxc.xmpp.chatState.setStatus = function(win, msg) {
  175. var statusMsgElement = win.find('.jsxc_status-msg');
  176. statusMsgElement.text(msg || '');
  177. statusMsgElement.attr('title', msg || '');
  178. if (msg) {
  179. statusMsgElement.addClass('jsxc_composing');
  180. win.addClass('jsxc_status-msg-show');
  181. } else {
  182. statusMsgElement.removeClass('jsxc_composing');
  183. win.removeClass('jsxc_status-msg-show');
  184. }
  185. };
  186. jsxc.xmpp.chatState.isDisabled = function() {
  187. var options = jsxc.options.get('chatState') || {};
  188. return !options.enable;
  189. };
  190. $(document).on('attached.jsxc', jsxc.xmpp.chatState.init);