PageRenderTime 44ms CodeModel.GetById 9ms RepoModel.GetById 0ms app.codeStats 0ms

/src/js/PusherChatWidget.js

https://gitlab.com/Rodoxx/test-pusher
JavaScript | 287 lines | 219 code | 36 blank | 32 comment | 20 complexity | 607c013e0635ec77e5bd24447fad766b MD5 | raw file
  1. /**
  2. * Creates an instance of a PusherChatWidget, binds to a chat channel on the pusher instance and
  3. * and creates the UI for the chat widget.
  4. *
  5. * @param {Pusher} pusher The Pusher object used for the chat widget.
  6. * @param {Map} options A hash of key value options for the widget.
  7. */
  8. function PusherChatWidget(pusher, options) {
  9. PusherChatWidget.instances.push(this);
  10. var self = this;
  11. this._pusher = pusher;
  12. this._autoScroll = true;
  13. options = options || {};
  14. this.settings = $.extend({
  15. maxItems: 50, // max items to show in the UI. Items beyond this limit will be removed as new ones come in.
  16. chatEndPoint: 'php/chat.php', // the end point where chat messages should be sanitized and then triggered
  17. statusEndPoint: 'php/status.php', // the end point where chat messages should be sanitized and then triggered
  18. channelName: document.location.href, // the name of the channel the chat will take place on
  19. appendTo: document.body, // A jQuery selector or object. Defines where the element should be appended to
  20. debug: true
  21. }, options);
  22. if(this.settings.debug && !Pusher.log) {
  23. Pusher.log = function(msg) {
  24. if(console && console.log) {
  25. console.log(msg);
  26. }
  27. }
  28. }
  29. // remove any unsupported characters from the chat channel name
  30. // see: http://pusher.com/docs/client_api_guide/client_channels#naming-channels
  31. this.settings.channelName = PusherChatWidget.getValidChannelName(this.settings.channelName);
  32. this._chatChannel = this._pusher.subscribe(this.settings.channelName);
  33. this._chatChannel.bind('chat_message', function(data) {
  34. self._chatMessageReceived(data);
  35. // Custom request for event
  36. $.ajax({
  37. url: 'php/status.php',
  38. type: 'post',
  39. dataType: 'json',
  40. data: {
  41. 'message_ok': data
  42. }
  43. });
  44. })
  45. this._itemCount = 0;
  46. this._widget = PusherChatWidget._createHTML(this.settings.appendTo);
  47. this._nicknameEl = this._widget.find('input[name=nickname]');
  48. this._emailEl = this._widget.find('input[name=email]');
  49. this._messageInputEl = this._widget.find('textarea');
  50. this._messagesEl = this._widget.find('ul');
  51. this._widget.find('button').click(function() {
  52. self._sendChatButtonClicked();
  53. })
  54. var messageEl = this._messagesEl;
  55. messageEl.scroll(function() {
  56. var el = messageEl.get(0);
  57. var scrollableHeight = (el.scrollHeight - messageEl.height());
  58. self._autoScroll = ( scrollableHeight === messageEl.scrollTop() );
  59. });
  60. this._startTimeMonitor();
  61. };
  62. PusherChatWidget.instances = [];
  63. /* @private */
  64. PusherChatWidget.prototype._chatMessageReceived = function(data) {
  65. var self = this;
  66. if(this._itemCount === 0) {
  67. this._messagesEl.html('');
  68. }
  69. var messageEl = PusherChatWidget._buildListItem(data);
  70. messageEl.hide();
  71. this._messagesEl.append(messageEl);
  72. messageEl.slideDown(function() {
  73. if(self._autoScroll) {
  74. var messageEl = self._messagesEl.get(0);
  75. var scrollableHeight = (messageEl.scrollHeight - self._messagesEl.height());
  76. self._messagesEl.scrollTop(messageEl.scrollHeight);
  77. }
  78. });
  79. ++this._itemCount;
  80. if(this._itemCount > this.settings.maxItems) {
  81. /* get first li of list */
  82. this._messagesEl.children(':first').slideUp(function() {
  83. $(this).remove();
  84. });
  85. }
  86. };
  87. /* @private */
  88. PusherChatWidget.prototype._sendChatButtonClicked = function() {
  89. var nickname = $.trim(this._nicknameEl.val()); // optional
  90. var email = $.trim(this._emailEl.val()); // optional
  91. if(!nickname) {
  92. alert('please supply a nickname');
  93. return;
  94. }
  95. var message = $.trim(this._messageInputEl.val());
  96. if(!message) {
  97. alert('please supply a chat message');
  98. return;
  99. }
  100. var chatInfo = {
  101. nickname: nickname,
  102. //email: email,
  103. text: message
  104. };
  105. this._sendChatMessage(chatInfo);
  106. };
  107. /* @private */
  108. PusherChatWidget.prototype._sendChatMessage = function(data) {
  109. var self = this;
  110. this._messageInputEl.attr('readonly', 'readonly');
  111. $.ajax({
  112. url: this.settings.chatEndPoint,
  113. type: 'post',
  114. dataType: 'json',
  115. data: {
  116. 'chat_info': data
  117. },
  118. complete: function(xhr, status) {
  119. Pusher.log('Chat message sent. Result: ' + status + ' : ' + xhr.responseText);
  120. if(xhr.status === 200) {
  121. self._messageInputEl.val('');
  122. }
  123. self._messageInputEl.removeAttr('readonly');
  124. },
  125. success: function(result) {
  126. var activity = result.activity;
  127. var imageInfo = activity.actor.image;
  128. var image = $('<div class="pusher-chat-widget-current-user-image">' +
  129. '<img src="' + imageInfo.url + '" width="32" height="32" />' +
  130. '</div>');
  131. var name = $('<div class="pusher-chat-widget-current-user-name">' + activity.actor.displayName.replace(/\\'/g, "'") + '</div>');
  132. var header = self._widget.find('.pusher-chat-widget-header');
  133. header.html(image).append(name);
  134. }
  135. })
  136. };
  137. /* @private */
  138. PusherChatWidget.prototype._startTimeMonitor = function() {
  139. var self = this;
  140. setInterval(function() {
  141. self._messagesEl.children('.activity').each(function(i, el) {
  142. var timeEl = $(el).find('a.timestamp span[data-activity-published]');
  143. var time = timeEl.attr('data-activity-published');
  144. var newDesc = PusherChatWidget.timeToDescription(time);
  145. timeEl.text(newDesc);
  146. });
  147. }, 10 * 1000)
  148. };
  149. /* @private */
  150. PusherChatWidget._createHTML = function(appendTo) {
  151. var html = '' +
  152. '<div class="pusher-chat-widget">' +
  153. '<div class="pusher-chat-widget-header">' +
  154. '<label for="nickname">Name</label>' +
  155. '<input type="text" name="nickname" />' +
  156. '</div>' +
  157. '<div class="pusher-chat-widget-messages">' +
  158. '<ul class="activity-stream">' +
  159. '<li class="waiting">No chat messages available</li>' +
  160. '</ul>' +
  161. '</div>' +
  162. '<div class="pusher-chat-widget-input">' +
  163. '<label for="message">Message</label>' +
  164. '<textarea name="message"></textarea>' +
  165. '<button class="pusher-chat-widget-send-btn">Send</button>' +
  166. '</div>' +
  167. '<div class="pusher-chat-widget-footer">' +
  168. '</div>' +
  169. '</div>';
  170. var widget = $(html);
  171. $(appendTo).append(widget);
  172. return widget;
  173. };
  174. /* @private */
  175. PusherChatWidget._buildListItem = function(activity) {
  176. var li = $('<li class="activity"></li>');
  177. li.attr('data-activity-id', activity.id);
  178. var item = $('<div class="stream-item-content"></div>');
  179. li.append(item);
  180. var imageInfo = activity.actor.image;
  181. var image = $('<div class="image">' +
  182. '<img src="' + imageInfo.url + '" width="' + imageInfo.width + '" height="' + imageInfo.height + '" />' +
  183. '</div>');
  184. item.append(image);
  185. var content = $('<div class="content"></div>');
  186. item.append(content);
  187. var user = $('<div class="activity-row">' +
  188. '<span class="user-name">' +
  189. '<a class="screen-name" title="' + activity.actor.displayName.replace(/\\'/g, "'") + '">' + activity.actor.displayName.replace(/\\'/g, "'") + '</a>' +
  190. //'<span class="full-name">' + activity.actor.displayName + '</span>' +
  191. '</span>' +
  192. '</div>');
  193. content.append(user);
  194. var message = $('<div class="activity-row">' +
  195. '<div class="text">' + activity.body.replace(/\\('|&quot;)/g, '$1') + '</div>' +
  196. '</div>');
  197. content.append(message);
  198. var time = $('<div class="activity-row">' +
  199. '<a ' + (activity.link?'href="' + activity.link + '" ':'') + ' class="timestamp">' +
  200. '<span title="' + activity.published + '" data-activity-published="' + activity.published + '">' + PusherChatWidget.timeToDescription(activity.published) + '</span>' +
  201. '</a>' +
  202. '<span class="activity-actions">' +
  203. /*'<span class="tweet-action action-favorite">' +
  204. '<a href="#" class="like-action" data-activity="like" title="Like"><span><i></i><b>Like</b></span></a>' +
  205. '</span>' +*/
  206. '</span>' +
  207. '</div>');
  208. content.append(time);
  209. return li;
  210. };
  211. /**
  212. * converts a string into something which can be used as a valid channel name in Pusher.
  213. * @param {String} from The string to be converted.
  214. *
  215. * @see http://pusher.com/docs/client_api_guide/client_channels#naming-channels
  216. */
  217. PusherChatWidget.getValidChannelName = function(from) {
  218. var pattern = /(\W)+/g;
  219. return from.replace(pattern, '-');
  220. }
  221. /**
  222. * converts a string or date parameter into a 'social media style'
  223. * time description.
  224. */
  225. PusherChatWidget.timeToDescription = function(time) {
  226. if(time instanceof Date === false) {
  227. time = new Date(Date.parse(time));
  228. }
  229. var desc = "dunno";
  230. var now = new Date();
  231. var howLongAgo = (now - time);
  232. var seconds = Math.round(howLongAgo/1000);
  233. var minutes = Math.round(seconds/60);
  234. var hours = Math.round(minutes/60);
  235. if(seconds === 0) {
  236. desc = "just now";
  237. }
  238. else if(minutes < 1) {
  239. desc = seconds + " second" + (seconds !== 1?"s":"") + " ago";
  240. }
  241. else if(minutes < 60) {
  242. desc = "about " + minutes + " minute" + (minutes !== 1?"s":"") + " ago";
  243. }
  244. else if(hours < 24) {
  245. desc = "about " + hours + " hour" + (hours !== 1?"s":"") + " ago";
  246. }
  247. else {
  248. desc = time.getDay() + " " + ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sept", "Oct", "Nov", "Dec"][time.getMonth()]
  249. }
  250. return desc;
  251. };