Spaces:
Running
Running
| {% extends 'base.html' %} {% block content %} | |
| <div id="room-container"> | |
| <div id="welcome-modal" class="modal"> | |
| <div class="modal-content"> | |
| <h3>Welcome!</h3> | |
| <p> | |
| Your display name for this chat session will be: | |
| <span id="displayNameText" style="font-weight:bold;"></span>. | |
| </p> | |
| <div class="modal-buttons"> | |
| <button class="modal-btn" id="welcomeOkBtn">OK</button> | |
| </div> | |
| </div> | |
| </div> | |
| <h1 id="home-header">Chat Room</h1> | |
| <div id="room-subsection"> | |
| <div class="topic-header-row"> | |
| <div class="topic-header-info"> | |
| <h2 id="room-code-display">Topic: <span class="topic-title">{{ topic_info.title }}</span> | |
| </h2> | |
| <div class="tooltip"> | |
| <button class="prompt-btn">Prompt</button> | |
| <span class="tooltiptext">{{topic_info.text}}</span> | |
| </div> | |
| </div> | |
| <div class="topic-header-buttons"> | |
| <button id="end-exp-btn">Chat Session Ends</button> | |
| <button id="abort-exp-btn">Abort Experiment</button> | |
| </div> | |
| </div> | |
| <div id="end-modal" class="modal"> | |
| <div class="modal-content"> | |
| <h3>Only Exit This Way When Instructed.</h3> | |
| <p>This signals the end of the chat session of the experiment. You will be redirected to the post-survey. This button is only to be used when the experiment ends, as indicated by the proctor. If you wish to exit the chat before instructed, use the "Abort Experiment" button instead.</p> | |
| <div class="modal-buttons"> | |
| <button class="modal-btn" id="endYesBtn">Continue</button> | |
| <button class="modal-btn" id="endNoBtn">Cancel</button> | |
| </div> | |
| </div> | |
| </div> | |
| <div id="abort-modal" class="modal"> | |
| <div class="modal-content"> | |
| <h3>Are you sure you want to leave this experiment?</h3> | |
| <p>This action is permanent. You will be redirected to the post-survey and will not be able to return to the chat room. However, if you do choose to leave, you will still receive the offered extra credit from your professor. If the chat session has ended, as signaled by the proctor, do NOT exit via this button. Use the "Chat Session Ends" button instead.</p> | |
| <div class="modal-buttons"> | |
| <button class="modal-btn" id="abortYesBtn">Yes</button> | |
| <button class="modal-btn" id="abortNoBtn">Cancel</button> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <div id="chat-room-widget"> | |
| <div id="msgs-container"> | |
| <ul id="messages"></ul> | |
| </div> | |
| <div id="message-box"> | |
| <textarea id="message-input" name="message" placeholder="Enter your message" rows="1"></textarea> | |
| <button type="submit" id="send-btn" onclick="sendMessage()">Send</button> | |
| </div> | |
| </div> | |
| <script type="text/javascript"> | |
| // Push a state when entering the page | |
| history.pushState(null, "", location.href); | |
| window.addEventListener("popstate", function () { | |
| // Immediately push another state to prevent backward navigation | |
| history.pushState(null, "", location.href); | |
| }); | |
| var socketio = io(); | |
| const chatEnded = {{ ended | tojson }}; | |
| const textarea = document.getElementById("message-input"); | |
| if (chatEnded) { | |
| textarea.disabled = true; | |
| textarea.placeholder = "The chat has ended."; | |
| document.getElementById("send-btn").disabled = true; | |
| document.getElementById("end-exp-btn").disabled = true; | |
| document.getElementById("abort-exp-btn").disabled = true; | |
| if (socketio) { | |
| socketio.close(); | |
| } | |
| } | |
| // Handler for the welcome modal | |
| let welcomeModal = document.getElementById("welcome-modal"); | |
| const displayNameText = document.getElementById("displayNameText"); | |
| displayNameText.textContent = "{{ user }}"; | |
| // Show the modal instantly when the page loads | |
| window.onload = function() { | |
| welcomeModal.style.display = "block"; | |
| }; | |
| // Close the modal on OK | |
| document.getElementById("welcomeOkBtn").onclick = function () { | |
| welcomeModal.style.display = "none"; | |
| }; | |
| // Creates the post-survey link (based on the bot names) | |
| const endpoint = "{{ url_for('post_survey') }}"; | |
| socketio.on("message", function (message) { createChatItem(message.message, message.sender) }); | |
| function createChatItem(message, sender) { | |
| //autoscroll capabilities | |
| const container = document.getElementById("msgs-container"); | |
| const shouldAutoScroll = isNearBottom(container); | |
| var messages = document.getElementById("messages"); | |
| var content; | |
| if (sender === "") { | |
| content = `<p class="member-activity">${message}</p>`; | |
| } else { | |
| var senderIsUser = "{{user}}" === sender; | |
| content = ` | |
| <li class="message-item ${senderIsUser ? "self-message-item" : "peer-message-item"}"> | |
| <p>${message}</p> | |
| <small class="${senderIsUser ? "chat-user-sender" : "chat-sender"}">${sender}</small> | |
| </li> | |
| `;} | |
| messages.insertAdjacentHTML("beforeend", content); | |
| //autoscroll capabilities | |
| if (shouldAutoScroll) { | |
| smoothScrollToBottom(container); | |
| } | |
| } | |
| function sendMessage() { | |
| var msgInput = document.getElementById("message-input"); | |
| if (msgInput.value === "") return; | |
| var msg = msgInput.value; | |
| socketio.emit("message", { message: msg }); | |
| msgInput.value = ""; | |
| msgInput.style.height = "auto"; // reset height | |
| } | |
| document.getElementById("message-input").addEventListener("keydown", function (event) { | |
| if (event.key === "Enter") { | |
| return | |
| // disabling send message so user can type a newline without sending | |
| //event.preventDefault(); // prevent a newline or form submit | |
| //sendMessage(); // call the same function as the Send button | |
| } | |
| }); | |
| textarea.addEventListener("input", () => { | |
| textarea.style.height = "auto"; // reset height | |
| textarea.style.overflowY = "hidden"; // start by hiding the scrollbar | |
| textarea.style.height = (textarea.scrollHeight + 8) + "px"; // set to fit content (+8 for bottom padding) | |
| // If we've hit the max height, allow scrolling | |
| if (textarea.scrollHeight > parseInt(getComputedStyle(textarea).maxHeight)) { | |
| textarea.style.overflowY = "auto"; | |
| } | |
| }); | |
| // Handler for the Experiment Ends confirmation pop-up | |
| const endModal = document.getElementById("end-modal"); | |
| document.getElementById("end-exp-btn").onclick = function () { | |
| endModal.style.display = "block"; | |
| }; | |
| document.getElementById("endNoBtn").onclick = function () { | |
| endModal.style.display = "none"; | |
| }; | |
| document.getElementById("endYesBtn").onclick = function (e) { | |
| //block browser confirmation popup | |
| e.stopPropagation(); | |
| // Redirect to ending survey | |
| window.open(endpoint, "_blank"); | |
| endModal.style.display = "none"; | |
| textarea.disabled = true; | |
| textarea.placeholder = "The chat has ended."; | |
| document.getElementById("send-btn").disabled = true; | |
| document.getElementById("end-exp-btn").disabled = true; | |
| document.getElementById("abort-exp-btn").disabled = true; | |
| if (socketio) { | |
| socketio.close(); | |
| } | |
| }; | |
| // Handler for the Abort Experiment confirmation pop-up | |
| let modal = document.getElementById("abort-modal"); | |
| document.getElementById("abort-exp-btn").onclick = function () { | |
| modal.style.display = "block"; | |
| }; | |
| document.getElementById("abortNoBtn").onclick = function () { | |
| modal.style.display = "none"; | |
| }; | |
| document.getElementById("abortYesBtn").onclick = function (e) { | |
| //block browser confirmation popup | |
| e.stopPropagation(); | |
| // Mark that user aborted and redirect to ending survey | |
| fetch("/abort", { method: "POST" }) | |
| .then(() => { | |
| window.open(endpoint, "_blank"); | |
| }); | |
| modal.style.display = "none"; | |
| textarea.disabled = true; | |
| textarea.placeholder = "The chat has ended."; | |
| document.getElementById("send-btn").disabled = true; | |
| document.getElementById("end-exp-btn").disabled = true; | |
| document.getElementById("abort-exp-btn").disabled = true; | |
| if (socketio) { | |
| socketio.close(); | |
| } | |
| }; | |
| // add auto scroll | |
| function isNearBottom(container, threshold = 120) { | |
| const distanceFromBottom = container.scrollHeight - (container.scrollTop + container.clientHeight); | |
| return distanceFromBottom < threshold; | |
| } | |
| function smoothScrollToBottom(container) { | |
| container.scrollTo({ top: container.scrollHeight, behavior: "smooth" }); | |
| } | |
| </script> | |
| <script type="text/javascript"> | |
| </script> | |
| </div> | |
| {% endblock %} | |