diff --git a/lumi2/static/js/group_edit.js b/lumi2/static/js/group_edit.js index 0ee4afa..1219069 100644 --- a/lumi2/static/js/group_edit.js +++ b/lumi2/static/js/group_edit.js @@ -1,143 +1,187 @@ -class AbstractUserEntry { - constructor(username, tableRow) { - this.username = username; - this.tableRow = tableRow; - this.membershipToggleButton = tableRow.querySelector(".toggleMembershipButton"); - this.membershipToggleButton.addEventListener("click", this.onButtonPress.bind(this)); - }; -}; +$(function() { + $("table").tablesorter({ + theme: 'bootstrap', + headerTemplate: '{content} {icon}', + cssIcon: 'bi-arrow-down-up', + cssIconNone: '', + cssIconAsc: 'bi-arrow-up', + cssIconDesc: 'bi-arrow-down', + }); +}); -function removeUserFromFormField(username) { - let formField = document.getElementById("updated_members"); - let oldMembersList = JSON.parse(formField.value); - let newMembersList = Array(); - for (let member of oldMembersList) { - if (member != username) { - newMembersList.push(member); +class UserEntry { + constructor(username, isMember, rowElement) { + this.username = username; + this.isMember = isMember; + this.rowElement = rowElement; + this.buttonElement = $(rowElement).find(".toggleMembershipButton"); + if (isMember) { + $(this.buttonElement).click(() => this.onClickLeave()); + } else { + $(this.buttonElement).click(() => this.onClickJoin()); } } - formField.value = JSON.stringify(newMembersList); - adjustLastMemberButtonState(); -}; -function addUserToFormField(username) { - let formField = document.getElementById("updated_members"); - let oldMembersList = JSON.parse(formField.value); - oldMembersList.push(username); - formField.value = JSON.stringify(oldMembersList); - adjustLastMemberButtonState(); -}; - -class MemberEntry extends AbstractUserEntry { - onButtonPress() { - this.tableRow.remove(); - createRemovedMemberRow(this.username); - removeUserFromFormField(this.username); - }; -}; - -class NonMemberEntry extends AbstractUserEntry { - onButtonPress() { - this.tableRow.remove(); - createAddedMemberRow(this.username); - addUserToFormField(this.username); - }; -}; - -function createRemovedMemberRow(username) { - let newTableRow = nonMembersTable.querySelector("tbody").insertRow(0); - newTableRow.className = "userEntry text-center bg-danger bg-gradient"; - newTableRow.id = username; - - let newTableHeader = document.createElement("th"); - newTableHeader.scope = "row"; - let newImage = document.createElement("img"); - newImage.src = `/static/images/users/${username}/thumbnail.jpg`; - newImage.alt = `Profile picture for user ${username}.`; - newImage.className = "img-fluid rounded"; - newImage.style = "max-width: 50px"; - newTableHeader.appendChild(newImage); - newTableRow.appendChild(newTableHeader); - - let newTableDataUsername = document.createElement("td"); - let newUsernameAnchor = document.createElement("a"); - newUsernameAnchor.href = `/users/view/${username}`; - newUsernameAnchor.textContent = username; - newTableDataUsername.appendChild(newUsernameAnchor); - newTableRow.appendChild(newTableDataUsername); - - - let newTableDataButton = document.createElement("td"); - let newTableButton = document.createElement("button"); - newTableButton.type = "button"; - newTableButton.className = "toggleMembershipButton inProgress btn btn-outline-light"; - newTableButton.disabled = true; - newTableButton.textContent = "Will be removed"; - newTableDataButton.appendChild(newTableButton); - newTableRow.appendChild(newTableDataButton); -}; - -function createAddedMemberRow(username) { - let newTableRow = membersTable.querySelector("tbody").insertRow(0); - newTableRow.className = "userEntry text-center bg-success bg-gradient"; - newTableRow.id = username; - - let newTableHeader = document.createElement("th"); - newTableHeader.scope = "row"; - let newImage = document.createElement("img"); - newImage.src = `/static/images/users/${username}/thumbnail.jpg`; - newImage.alt = `Profile picture for user ${username}.`; - newImage.className = "img-fluid rounded"; - newImage.style = "max-width: 50px"; - newTableHeader.appendChild(newImage); - newTableRow.appendChild(newTableHeader); - - let newTableDataUsername = document.createElement("td"); - let newUsernameAnchor = document.createElement("a"); - newUsernameAnchor.href = `/users/view/${username}`; - newUsernameAnchor.textContent = username; - newTableDataUsername.appendChild(newUsernameAnchor); - newTableRow.appendChild(newTableDataUsername); - - - let newTableDataButton = document.createElement("td"); - let newTableButton = document.createElement("button"); - newTableButton.type = "button"; - newTableButton.className = "toggleMembershipButton inProgress btn btn-outline-light"; - newTableButton.disabled = true; - newTableButton.textContent = "Will be added"; - newTableDataButton.appendChild(newTableButton); - newTableRow.appendChild(newTableDataButton); -}; - -/** - * If there is only one member in the group member table, disables that member's - * remove button. - * If there is more than one member, activates the removal button. - */ -function adjustLastMemberButtonState() { - memberRows = membersTable.querySelectorAll(".userEntry"); - if (memberRows.length == 1) { - memberRows[0].querySelector(".toggleMembershipButton").disabled = true; - } else { - for (let button of membersTable.querySelectorAll(".toggleMembershipButton")) { - if (!button.className.includes("inProgress")) { - button.disabled = false; + onClickLeave() { + // Deactivate the last remaining member's togglebutton before leaving + if ($(membersTable).find(".userEntry").length < 2) { + for (entry of $(membersTable).find(".userEntry")) { + if ($(entry).id != this.username) { + $(entry).find(".toggleMembershipButton")[0].prop("disabled", true); + } } } + + this.setButtonAppearanceInProgress(); + + $.ajax({ + context: { + "userEntry": this + }, + url: `/api/group/${groupname}`, + type: "GET", + dataType: "json", + }).done(function(groupJson) { + $.ajax({ + context: { + "userEntry": this.userEntry, + }, + url: `/api/group/${groupname}`, + type: "PUT", + dataType: "json", + data: JSON.stringify(groupJson), + contentType: "application/json", + }) + .done(function(groupJson) { + this.userEntry.isMember = false; + $(this.userEntry.buttonElement).off("click"); + $(this.userEntry.buttonElement).click(() => this.userEntry.onClickJoin()); + $(this.userEntry.rowElement).prependTo($("#tableNonMembers").find("tbody")); + this.userEntry.setButtonAppearanceJoinGroup(); + }) + .fail(function(xhr, status, errorThrown) { + console.log(`Error: ${errorThrown}`); + console.log(`Status: ${status}`); + console.dir(xhr); + alert("Sorry, there was a problem sending information to the server."); + + this.userEntry.setButtonAppearanceLeaveGroup(); + }); + }).fail(function(xhr, status, errorThrown) { + console.log(`Error: ${errorThrown}`); + console.log(`Status: ${status}`); + alert("Sorry, there was a problem retrieving information from the server."); + + this.userEntry.setButtonAppearanceLeaveGroup(); + }); + } + + onClickJoin() { + this.setButtonAppearanceInProgress(); + + $.ajax({ + context: { + "userEntry": this + }, + url: `/api/group/${groupname}`, + type: "GET", + dataType: "json", + }).done(function(groupJson) { + // Add current user to the members array + groupJson.group.members.push(this.userEntry.username); + $.ajax({ + context: { + "userEntry": this.userEntry, + }, + url: `/api/group/${groupname}`, + type: "PUT", + dataType: "json", + data: JSON.stringify(groupJson), + contentType: "application/json", + }) + .done(function(groupJson) { + this.userEntry.isMember = true; + $(this.userEntry.buttonElement).off("click"); + $(this.userEntry.buttonElement).click(() => this.userEntry.onClickLeave()); + $(this.userEntry.rowElement).prependTo($("#tableMembers").find("tbody")); + this.userEntry.setButtonAppearanceLeaveGroup(); + }) + .fail(function(xhr, status, errorThrown) { + console.log(`Error: ${errorThrown}`); + console.log(`Status: ${status}`); + console.dir(xhr); + alert("Sorry, there was a problem sending information to the server."); + + this.userEntry.setButtonAppearanceJoinGroup(); + }); + }).fail(function(xhr, status, errorThrown) { + console.log(`Error: ${errorThrown}`); + console.log(`Status: ${status}`); + alert("Sorry, there was a problem retrieving information from the server."); + this.userEntry.setButtonAppearanceJoinGroup(); + }); + } + + setButtonAppearanceInProgress() { + this.buttonElement.removeClass("btn-danger btn-success btn-secondary"); + this.buttonElement.addClass("btn-secondary"); + this.buttonElement.empty(); + this.buttonElement.html( + '' + + ' Loading...' + ); + } + + setButtonAppearanceLeaveGroup() { + this.buttonElement.removeClass("btn-danger btn-success btn-secondary"); + this.buttonElement.addClass("btn-danger"); + this.buttonElement.empty(); + this.buttonElement.html( + ' Remove from group' + ); + } + + setButtonAppearanceJoinGroup() { + this.buttonElement.removeClass("btn-danger btn-success btn-secondary"); + this.buttonElement.addClass("btn-success"); + this.buttonElement.empty(); + this.buttonElement.html( + ' Add to group' + ); } } -const membersTable = document.getElementById("groupMembers"); -const nonMembersTable = document.getElementById("groupNonMembers"); -let memberEntries = new Set(); -let nonMemberEntries = new Set(); +function getUserEntries() { + let userEntries = []; -for (let userEntry of document.body.querySelectorAll(".userEntry")) { - if (userEntry.parentElement.parentElement.id === "groupMembers") { - memberEntries.add(new MemberEntry(userEntry.id, userEntry)); - } else if (userEntry.parentElement.parentElement.id === "groupNonMembers") { - nonMemberEntries.add(new NonMemberEntry(userEntry.id, userEntry)); + // Construct member entries + for (let entry of membersTable.find("tbody").find(".userEntry")) { + userEntries.push(new UserEntry( + entry.id, + true, + entry + )); } + + // Construct nonmember entries + for (let entry of nonMembersTable.find("tbody").find(".userEntry")) { + userEntries.push(new UserEntry( + entry.id, + false, + entry + )); + } + + return userEntries; } -adjustLastMemberButtonState(); + +let nonMembersTable = undefined; +let membersTable = undefined; +let entries = undefined; +const groupname = window.location.pathname.split("/").pop(); + +$(document).ready(function() { + nonMembersTable = $("#tableNonMembers"); + membersTable = $("#tableMembers"); + entries = getUserEntries(); +}); diff --git a/lumi2/static/js/tables.js b/lumi2/static/js/tables.js deleted file mode 100644 index 909aa32..0000000 --- a/lumi2/static/js/tables.js +++ /dev/null @@ -1,10 +0,0 @@ -$(function() { - $("table").tablesorter({ - theme: 'bootstrap', - headerTemplate: '{content} {icon}', - cssIcon: 'bi-arrow-down-up', - cssIconNone: '', - cssIconAsc: 'bi-arrow-up', - cssIconDesc: 'bi-arrow-down', - }); -}); diff --git a/lumi2/templates/usermanager/group_edit.html b/lumi2/templates/usermanager/group_edit.html index 9faa074..d89d73b 100644 --- a/lumi2/templates/usermanager/group_edit.html +++ b/lumi2/templates/usermanager/group_edit.html @@ -4,13 +4,11 @@
Add or remove members from {{ groupname }} here. Hit the Apply button to save your changes.
-Note that Groups must always have at least one member.
Other users | @@ -31,7 +29,7 @@
---|
{{ groupname }} | @@ -61,7 +59,7 @@
---|