chat.ejs 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178
  1. <div class="chats-container">
  2. <div class="chat-header">
  3. <a href="/" class="action">
  4. <img src="/img/back.png" />
  5. </a>
  6. <span class="chat-title"><%- title %></span>
  7. </div>
  8. <div id="message-list" class="message-list">
  9. <% if (empty) { %>
  10. <p class="empty-label">No messages</p>
  11. <% } %>
  12. <% messages.forEach(function(message) { %>
  13. <% if (message.username === username) { %>
  14. <div class="message align-end">
  15. <% if (message.attachment) { %>
  16. <a href="/attachment/<%- message.attachment %>" target="_blank">
  17. <img src="/thumbnail/<%- message.attachment %>" />
  18. </a>
  19. <% } %>
  20. <span class="message-text user-message">
  21. <% } else { %>
  22. <div class="message align-start">
  23. <span class="message-text friend-message">
  24. <% } %>
  25. <%- message.text %>
  26. </span>
  27. <span class="message-datetime"><%- message.datetime %></span>
  28. </div>
  29. <% }); %>
  30. <% if (hasMoreMessages) { %>
  31. <form id="load-more" onsubmit="return onLoadMoreClick(event)">
  32. <input type="submit" value="Load More" class="load-more" />
  33. </form>
  34. <% } %>
  35. </div>
  36. <div id="attachment-preview">
  37. <span id="attachment-filename"></span>
  38. <span onclick="onAttachmentClose(event)" id="attachment-close" class="action">
  39. <img src="/img/close.png" />
  40. </span>
  41. </div>
  42. <form onsubmit="return onMessageSubmit(event)" class="input-form">
  43. <label for="message-attachment" class="action">
  44. <img src="/img/clip.png" />
  45. </label>
  46. <input type="file" id="message-attachment" name="attachment" onchange="onAttachmentChange(this)" accept=".jpg, .jpeg, .png, .webp, .avif" />
  47. <input type="text" id="message-input" name="text" placeholder="Enter message..." class="text-input" autocomplete="off" required />
  48. <input type="submit" value="Send" class="button" />
  49. </form>
  50. <span id="version" class="version">SvinChat v<%- version %></span>
  51. </div>
  52. <script>
  53. var pollRequest = null
  54. var firstTimestamp = new Date("<%- firstTimestamp %>").toISOString()
  55. var lastTimestamp = new Date().toISOString()
  56. var version = document.getElementById("version")
  57. var loadMoreForm = document.getElementById("load-more")
  58. var messageList = document.getElementById("message-list")
  59. var messageInput = document.getElementById("message-input")
  60. var attachmentInput = document.getElementById("message-attachment")
  61. var attachmentName = document.getElementById("attachment-filename")
  62. var timestamps = document.getElementsByClassName("message-datetime")
  63. for (var i = 0; i < timestamps.length; i++) {
  64. var timestamp = timestamps[i]
  65. timestamp.innerText = new Date(timestamp.innerText).toLocaleString()
  66. }
  67. function addMessage(message, target) {
  68. var container = document.createElement("div")
  69. var textSpan = document.createElement("span")
  70. var datetimeSpan = document.createElement("span")
  71. if (message.username === "<%- username %>") {
  72. container.className = "message align-end"
  73. textSpan.className = "message-text user-message"
  74. } else {
  75. container.className = "message align-start"
  76. textSpan.className = "message-text friend-message"
  77. }
  78. datetimeSpan.className = "message-datetime"
  79. textSpan.innerText = message.text
  80. datetimeSpan.innerText = new Date(message.datetime).toLocaleString()
  81. if (message.attachment) {
  82. var attachmentLink = document.createElement("a")
  83. attachmentLink.href = "/attachment/" + message.attachment
  84. attachmentLink.target = "_blank"
  85. var attachmentImg = document.createElement("img")
  86. attachmentImg.src = "/thumbnail/" + message.attachment
  87. attachmentLink.appendChild(attachmentImg)
  88. container.appendChild(attachmentLink)
  89. }
  90. container.appendChild(textSpan)
  91. container.appendChild(datetimeSpan)
  92. messageList.insertBefore(container, target)
  93. setTimeout(function () {
  94. container.scrollIntoView()
  95. }, 500)
  96. }
  97. function onMessageSubmit(event) {
  98. event.preventDefault()
  99. var formData = new FormData()
  100. formData.append("username", "<%- username %>")
  101. formData.append("text", messageInput.value)
  102. formData.append("datetime", new Date().toISOString())
  103. if (attachmentInput.files.length > 0) {
  104. formData.append("attachment", attachmentInput.files[0])
  105. }
  106. var xhr = new XMLHttpRequest()
  107. xhr.open("POST", "/chat/<%- title %>")
  108. xhr.send(formData)
  109. messageInput.value = ""
  110. messageInput.focus()
  111. onAttachmentClose()
  112. return false
  113. }
  114. function pollMessages() {
  115. var data = { timestamp: lastTimestamp }
  116. pollRequest = new XMLHttpRequest()
  117. pollRequest.timeout = 30000
  118. pollRequest.open("POST", "/poll/<%- chatId %>")
  119. pollRequest.setRequestHeader("Content-Type", "application/json;charset=UTF-8")
  120. pollRequest.onload = function () {
  121. var response = JSON.parse(pollRequest.responseText)
  122. for (var i = 0; i < response["messages"].length; i++) {
  123. var message = response["messages"][i]
  124. lastTimestamp = message.datetime
  125. addMessage(message, messageList.firstChild)
  126. }
  127. pollMessages()
  128. }
  129. pollRequest.ontimeout = function (e) {
  130. pollMessages()
  131. }
  132. pollRequest.send(JSON.stringify(data))
  133. }
  134. function onLoadMoreClick(event) {
  135. event.preventDefault()
  136. var data = { timestamp: firstTimestamp }
  137. var loadMoreRequest = new XMLHttpRequest()
  138. loadMoreRequest.open("POST", "/chat/<%- title %>/messages")
  139. loadMoreRequest.setRequestHeader("Content-Type", "application/json;charset=UTF-8")
  140. loadMoreRequest.onload = function () {
  141. var response = JSON.parse(loadMoreRequest.responseText)
  142. if (response.messages.length > 0) {
  143. for (var i = 0; i < response["messages"].length; i++) {
  144. var message = response["messages"][i]
  145. addMessage(message, messageList.lastChild)
  146. }
  147. firstTimestamp = response.timestamp
  148. messageList.insertBefore(loadMoreForm, messageList.lastChild)
  149. if (!response.hasMoreMessages) {
  150. loadMoreForm.style.display = "none"
  151. }
  152. } else {
  153. loadMoreForm.style.display = "none"
  154. }
  155. }
  156. loadMoreRequest.send(JSON.stringify(data))
  157. return false
  158. }
  159. function onAttachmentChange(event) {
  160. attachmentName.textContent = event.files[0].name
  161. }
  162. function onAttachmentClose(event) {
  163. attachmentName.textContent = ""
  164. attachmentInput.value = ""
  165. }
  166. messageInput.addEventListener("focus", function (e) {
  167. setTimeout(function () {
  168. version.scrollIntoView()
  169. }, 500)
  170. })
  171. window.addEventListener("pageshow", function (e) {
  172. messageList.firstElementChild.scrollIntoView(false)
  173. pollMessages()
  174. })
  175. window.addEventListener("pagehide", function (e) {
  176. pollRequest.abort()
  177. })
  178. </script>