riderle's picture
Update chat_application/templates/room.html
3d4b454 verified
{% 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>
<div id="timer-modal" class="modal">
<div class="modal-content">
<h3>Start a Timer</h3>
<p><strong>Please start a timer for 20 minutes</strong>. At the 20 minute mark, you may click the button "End Chat Session" to continue with the study.</p>
<div class="modal-buttons">
<button class="modal-btn" id="timerOkBtn">I have set a timer for 20 minutes.</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>
<div class="topic-header-buttons">
<button id="end-exp-btn">End Chat Session</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 After 20 Minutes of Participation in the Chatroom.</h3>
<p>This signals the end of the chat session of the experiment. You will be redirected to the post-survey.</p>
<p>This button is only to be used at the end of your 20 minutes of participation in the chatroom. <strong>If you wish to exit the chat before finishing your 20 minutes, use the "Abort Experiment" button instead.</strong></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.</p>
<p><strong>If you finished your 20 minutes in the chatroom, do NOT exit via this button. Use the "End Chat Session" button instead.</strong></p>
<div class="modal-buttons">
<button class="modal-btn" id="abortYesBtn-pre">Yes</button>
<button class="modal-btn" id="abortNoBtn-pre">Cancel</button>
</div>
</div>
</div>
<div id="abort-modal-confirm" class="modal">
<div class="modal-content">
<h3>Confirmation</h3>
<p>By clicking yes, you will exit the experiment <strong>without</strong> completing the final survey.</p>
<p>We encourage you to message us about any concerns or to <a href="{{ feedback_form_url | default('https://umw.qualtrics.com/jfe/form/SV_08v26NssCOwZTP8') }}" target="_blank">provide feedback here</a>.</p>
<div class="modal-buttons">
<button class="modal-btn" id="abortYesBtn">End early with code "C9V2XFDU"</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");
let timerModal = document.getElementById("timer-modal");
const displayNameText = document.getElementById("displayNameText");
displayNameText.textContent = "{{ user }}";
// Show the modal instantly when the page loads
window.onload = function() {
timerModal.style.display = "block";
};
//timer pop-up
document.getElementById("timerOkBtn").onclick = function () {
timerModal.style.display = "none";
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') }}";
const endpointQuitEarly = "https://app.prolific.com/submissions/complete?cc=C9V2XFDU";
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");
let abortModalConfirm = document.getElementById("abort-modal-confirm");
document.getElementById("abort-exp-btn").onclick = function () {
modal.style.display = "block";
};
document.getElementById("abortYesBtn-pre").onclick = function () {
abortModalConfirm.style.display = "block";
modal.style.display = "none";
};
document.getElementById("abortNoBtn-pre").onclick = function () {
modal.style.display = "none";
};
document.getElementById("abortYesBtn-SurveyAnyway").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();
}
abortModalConfirm.style.display = "none";
};
document.getElementById("abortNoBtn").onclick = function () {
abortModalConfirm.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(endpointQuitEarly, "_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();
}
abortModalConfirm.style.display = "none";
};
document.getElementById("abortNoBtn").onclick = function () {
abortModalConfirm.style.display = "none";
};
// 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">
const initialMessages = {{ messages | tojson }};
initialMessages.forEach(msg => {
createChatItem(msg.message, msg.sender);
});
</script>
</div>
{% endblock %}