Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions bases/rsptx/interactives/runestone/mchoice/js/mchoice.js
Original file line number Diff line number Diff line change
Expand Up @@ -417,7 +417,7 @@ export default class MultipleChoice extends RunestoneBase {
studentVoteCount > 1) {
this.renderMCMAFeedBack();
} else {
$(this.feedBackDiv).html("<p>Your Answer has been recorded</p>");
$(this.feedBackDiv).html("<p>Your answer has been recorded</p>");
$(this.feedBackDiv).attr("class", "alert alert-info");
}
}
Expand Down Expand Up @@ -572,7 +572,7 @@ export default class MultipleChoice extends RunestoneBase {
studentVoteCount > 1) {
this.renderMCMAFeedBack();
} else {
$(this.feedBackDiv).html("<p>Your Answer has been recorded</p>");
$(this.feedBackDiv).html("<p>Your answer has been recorded</p>");
$(this.feedBackDiv).attr("class", "alert alert-info");
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -711,6 +711,7 @@ def peer_async():
qnum = int(request.vars.question_num)

current_question, all_done = _get_numbered_question(assignment_id, qnum)
assignment = db(db.assignments.id == assignment_id).select().first()
course = db(db.courses.course_name == auth.user.course_name).select().first()
course_attrs = getCourseAttributesDict(course.id, course.base_course)
if "latex_macros" not in course_attrs:
Expand All @@ -721,6 +722,7 @@ def peer_async():
course=get_course_row(db.courses.ALL),
current_question=current_question,
assignment_id=assignment_id,
assignment_name = assignment.name,
nextQnum=qnum + 1,
all_done=all_done,
**course_attrs,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
#pi-instructor-interface .row, #pi-instructor-interface #imessage {
/* +--------------------------------+ */
/* | Peer Instruction (PI) Stylesheet | */
/* +--------------------------------+ */

/* ---------------------- */
/* Instructor's interface */
/* ---------------------- */
#pi-instructor-interface .row, #pi-instructor-interface #imessage {
margin-right: 0px;
margin-left: 0px;
padding-left: 15px;
Expand Down Expand Up @@ -158,4 +164,172 @@

.autopermalink {
display: none;
}

/* ------------------- */
/* Student's interface */
/* ------------------- */
#pi-student-interface .row, #pi-student-interface #imessage {
margin-right: 0px;
margin-left: 0px;
padding-right: 15px;
}

#discussion_panel {
margin: 20px 0;
background: #FBFBFB;
border: 0.5px solid #C7CDD1;
border-radius: 12px;
box-shadow: 0px 20px 24px 0px rgba(17, 17, 17, 0.06);
padding-left: 0px;
padding-right: 0px;
}

#discussion-panel-heading {
font-size: 22px;
font-weight: 500;
padding: 12px 24px;
background: #FBFBFB;
border: 1px solid #C7CDD1;
border-radius: 12px 12px 0px 0px;
box-shadow: 0px 2px 2px 0px rgba(17, 17, 17, 0.06);
}

#discussion-panel-heading p {
margin: 0;
}

#discussion-panel-peer-votes {
border-bottom: 1px solid #C7CDD1;
padding: 16px 24px;
}

#discussion-panel-peer-votes-content {
border-radius: 12px;
border: 2px solid #C7CDD1;
background: #FFFFFF;
padding: 16px 32px;
}

#discussion-panel-peer-votes-content p {
margin: 0;
line-height: 28px;
}

#discussion-panel-peer-votes-content #peerlist {
margin-bottom: 8px;
}

#discussion-panel-messages {
padding: 16px 24px;
}

#discussion-panel-messages #messages {
margin: 0;
padding-left: 0;
padding-right: 10px;
min-height: 15vh;
max-height: 35vh;
overflow-y: auto;
display: flex;
flex-direction: column;
}

#discussion-panel-messages #messages > li {
margin-top: 8px;
}

#discussion-panel-messages #messages .outgoing-mess + .incoming-mess,
#discussion-panel-messages #messages .incoming-mess + .outgoing-mess {
margin-top: 16px;
}

#discussion-panel-messages #messages > li:first-child {
margin-top: 0;
}

#discussion-panel-messages #messages .outgoing-mess, #discussion-panel-messages #messages .incoming-mess {
display: flex;
flex-direction: column;
font-style: normal;
color: #333;
gap: 4px;
}

#discussion-panel-messages #messages .outgoing-mess {
align-items: end;
}

#discussion-panel-messages #messages .incoming-mess {
align-items: start;
}

#discussion-panel-messages #messages .sender {
display: flex;
font-size: 11px;
gap: 8px;
align-items: center;
}

#discussion-panel-messages #messages .sender-initials {
display: flex;
background: #777777;
height: 24px;
width: 24px;
border-radius: 50%;
align-items: center;
justify-content: center;
color: #FFFFFF;
}

#discussion-panel-messages #messages .sender-name {
font-weight: 700;
}

#discussion-panel-messages #messages .content {
border-radius: 15px;
padding: 8px 16px;
}

#discussion-panel-messages #messages .outgoing-mess .sender-initials {
order: 2;
}

#discussion-panel-messages #messages .outgoing-mess .content {
background: rgba(215, 241, 249, 0.60);
}

#discussion-panel-messages #messages .incoming-mess .content {
background: rgba(255, 255, 215, 0.60);
}

#peer-message-box {
display: flex;
flex-direction: row;
align-items: center;
justify-content: space-between;
width: 100%;
border-radius: 12px;
border: 2px solid #C7CDD1;
background: #FFFFFF;
padding: 8px 16px;
margin-top: 10px;
gap: 16px;
}

#peer-message-box input {
width: 100%;
border: none;
}

#sendpeermsg {
background: none;
margin: 0;
padding: 0;
display: flex;
}

#sendpeermsg.disabled {
pointer-events: none;
opacity: 0.5;
}
110 changes: 88 additions & 22 deletions bases/rsptx/web2py_server/applications/runestone/static/js/peer.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Configuration for the PI steps and helper functions to handle step progression
// Configuration for the PI steps and helper functions to handle step progression in the instructor's interface
const STEP_CONFIG = {
vote1: {
next: ['makep', 'facechat', 'makeabgroups'],
Expand Down Expand Up @@ -107,6 +107,42 @@ function handleButtonClick(event) {
}
}

// Function to render incoming and outgoing messages for the text chat
function renderMessage({ from, text, direction }) {
// Create message element
const message = document.createElement("li");
message.classList.add(`${direction}-mess`);

// Sender container
const sender = document.createElement("div");
sender.classList.add("sender");

// Thumbnail using sender initials
const senderInitials = document.createElement("div");
senderInitials.classList.add("sender-initials");
let initials = from.split(" ").map(n => n.charAt(0)).join("").toUpperCase();
senderInitials.textContent = initials;

// Sender name
const senderName = document.createElement("div");
senderName.classList.add("sender-name");
senderName.textContent = direction === "outgoing" ? "You" : from;

sender.appendChild(senderInitials);
sender.appendChild(senderName);

// Message content
const content = document.createElement("div");
content.classList.add("content");
content.textContent = text;

// Append sender and content to message
message.appendChild(sender);
message.appendChild(content);

return message;
}

var ws = null;
var alertSet = false;
function connect(event) {
Expand All @@ -119,15 +155,13 @@ function connect(event) {
ws.onclose = function () {
console.log("Websocket Closed")
alert(
"You have been disconnected from the peer instruction server. Will Reconnect."
"You have been disconnected from the peer instruction server. Will reconnect."
);
connect();
};

ws.onmessage = function (event) {
var messages = document.getElementById("messages");
var message = document.createElement("li");
message.classList.add("incoming-mess");
const messages = document.getElementById("messages");
let mess = JSON.parse(event.data);
// This is an easy to code solution for broadcasting that could go out to
// multiple courses. It would be better to catch that on the server side
Expand All @@ -138,9 +172,15 @@ function connect(event) {
}
if (mess.type === "text") {
if (!(mess.time in messageTrail)) {
var content = document.createTextNode(`${mess.from}: ${mess.message}`);
message.appendChild(content);
let message = renderMessage({
from: mess.from,
text: mess.message,
direction: "incoming"
});

// Append message to messages container
messages.appendChild(message);
messages.scrollTop = messages.scrollHeight;
messageTrail[mess.time] = mess.message;
}
} else if (mess.type === "control") {
Expand Down Expand Up @@ -275,7 +315,7 @@ function connect(event) {
for (const key in adict) {
let currAnswer = adict[key];
let newpeer = document.createElement("p");
newpeer.innerHTML = `${key} answered ${currAnswer}`;
newpeer.innerHTML = `${key}: <strong>${currAnswer}</strong>`;
peerlist.appendChild(newpeer);
}
break;
Expand Down Expand Up @@ -396,31 +436,43 @@ async function sendLtiScores(event) {
// the server can then broadcast the message or send it to a
// specific user
async function sendMessage(event) {
var input = document.getElementById("messageText");
if (input.value.trim() === "") {
const messages = document.getElementById("messages");
const input = document.getElementById("messageText");
const sendButton = document.getElementById("sendpeermsg");
const messageText = input.value.trim();

if (messageText === "") {
input.focus();
return;
}

let mess = {
type: "text",
from: `${user}`,
message: input.value,
message: messageText,
time: Date.now(),
broadcast: false,
course_name: eBookConfig.course,
div_id: currentQuestion,
};

await publishMessage(mess);
var messages = document.getElementById("messages");
var message = document.createElement("li");
message.classList.add("outgoing-mess");
var content = document.createTextNode(`${user}: ${input.value}`);
message.appendChild(content);

let message = renderMessage({
from: user,
text: messageText,
direction: "outgoing"
});

// Append message to messages container
messages.appendChild(message);
messages.scrollTop = messages.scrollHeight;

input.value = "";
// focus tehe input box again
input.focus();
// not needed for onclick event.preventDefault()

// Disable the send button after sending a message
sendButton.classList.add("disabled");
}

function warnAndStopVote(event) {
Expand Down Expand Up @@ -731,11 +783,25 @@ async function setupPeerGroup() {

$(function () {
let tinput = document.getElementById("messageText");
if (tinput) {
tinput.addEventListener("keyup", function (event) {
if (event.keyCode === 13) {
let sendButton = document.getElementById("sendpeermsg");

if (tinput && sendButton) {
tinput.addEventListener("input", function () {
let message = this.value.trim();
if (message !== "") {
sendButton.classList.remove("disabled");
} else {
sendButton.classList.add("disabled");
}
});

tinput.addEventListener("keydown", function (event) {
if (event.key === "Enter") {
event.preventDefault();
document.getElementById("sendpeermsg").click();
let message = this.value.trim();
if (message != "") {
document.getElementById("sendpeermsg").click();
}
}
});
}
Expand Down
Loading