chat.ejs 7.7 KB

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