').text("Open")
)
).hide();
closestRow.after(object);
// Hide the 'edit' button for non-owners and -editors
let currentAuth = this.authorizationsFiltered[closestRow.index(".project-row")];
if (currentAuth.authorizationLevel !== "OWN") {
$(".project-view .inline-btn.edit").hide();
}
object.find(".edit").click(() => {
this.windowController.showEditProjectWindow(simAuthorizations);
});
object.find(".open").click(() => {
ProjectsController.openProject(currentAuth);
});
closestRow.addClass("active");
object.slideDown(200);
});
}
/**
* Controls the filtered authorization list, based on clicks from the side menu.
*/
private handleFilterClick(): void {
$(".all-projects").on("click", () => {
this.goToAllProjects();
});
$(".my-projects").on("click", () => {
this.goToMyProjects();
});
$(".shared-projects").on("click", () => {
this.goToSharedProjects();
});
this.goToAllProjects();
}
/**
* Show a list containing all projects (regardless of the authorization level the user has over them).
*/
private goToAllProjects(): void {
this.authorizationsFiltered = this.authorizations;
ProjectsController.populateList(this.authorizations);
this.updateNoProjectsAlert();
ProjectsController.activateFilterViewButton($(".all-projects"));
}
/**
* Show a list containing only projects that the user owns.
*/
private goToMyProjects(): void {
this.authorizationsFiltered = ProjectsController.filterList(this.authorizations, true);
ProjectsController.populateList(this.authorizationsFiltered);
this.updateNoProjectsAlert();
ProjectsController.activateFilterViewButton($(".my-projects"));
}
/**
* Show a list containing only projects that the user does not own (but can edit or view).
*/
private goToSharedProjects(): void {
this.authorizationsFiltered = ProjectsController.filterList(this.authorizations, false);
ProjectsController.populateList(this.authorizationsFiltered);
this.updateNoProjectsAlert();
ProjectsController.activateFilterViewButton($(".shared-projects"));
}
}
/**
* Controller class responsible for rendering the project add/edit window and handle user interaction with it.
*/
class WindowController {
private projectsController: ProjectsController;
private windowOverlay: JQuery;
private window: JQuery;
private table: JQuery;
private closeCallback: () => any;
private simAuthorizations: IAuthorization[];
private simulationId: number;
private editMode: boolean;
private api: APIController;
constructor(projectsController: ProjectsController, api: APIController) {
this.projectsController = projectsController;
this.windowOverlay = $(".window-overlay");
this.window = $(".projects-window");
this.table = $(".participants-table");
this.projectsController.windowController = this;
this.simAuthorizations = [];
this.editMode = false;
this.api = api;
$(".window-footer .btn").hide();
$(".participant-add-form").submit((event: JQueryEventObject) => {
event.preventDefault();
$(".participant-add-form .btn").trigger("click");
});
$(".project-name-form").submit((event: JQueryEventObject) => {
event.preventDefault();
$(".project-name-form .btn").trigger("click");
});
// Clean-up actions to occur after every window-close
this.closeCallback = () => {
this.table.empty();
$(".project-name-form .btn").off();
$(".participant-add-form .btn").off();
$(".window-footer .btn").hide().off();
$(".participant-email-alert").hide();
$(".participant-level div").removeClass("active").off();
this.table.off("click", ".participant-remove div");
$(".project-name-form input").val("");
$(".participant-add-form input").val("");
if (this.editMode) {
this.projectsController.updateAuthorizations();
}
};
$(".new-project-btn").click(() => {
this.showAddProjectWindow();
});
// Stop click events on the window from closing it indirectly
this.window.click((event: JQueryEventObject) => {
event.stopPropagation();
});
$(".window-close, .window-overlay").click(() => {
this.closeWindow();
});
}
/**
* Displays a window for project edits (used for adding participants and changing the name).
*
* @param authorizations The authorizations of the simulation project to be edited.
*/
public showEditProjectWindow(authorizations: IAuthorization[]): void {
this.editMode = true;
this.simAuthorizations = [];
this.simulationId = authorizations[0].simulation.id;
// Filter out the user's authorization from the authorization list (not to be displayed in the list)
authorizations.forEach((authorization: IAuthorization) => {
if (authorization.userId !== this.projectsController.currentUserId) {
this.simAuthorizations.push(authorization);
}
});
$(".window .window-heading").text("Edit project");
$(".project-name-form input").val(authorizations[0].simulation.name);
$(".project-name-form .btn").css("display", "inline-block").click(() => {
let nameInput = $(".project-name-form input").val();
if (nameInput !== "") {
authorizations[0].simulation.name = nameInput;
this.api.updateSimulation(authorizations[0].simulation);
}
});
$(".project-open-btn").show().click(() => {
ProjectsController.openProject({
userId: this.projectsController.currentUserId,
simulationId: this.simulationId,
authorizationLevel: "OWN"
});
});
$(".project-delete-btn").show().click(() => {
this.api.deleteSimulation(authorizations[0].simulationId).then(() => {
this.projectsController.updateAuthorizations();
this.closeWindow();
});
});
$(".participant-add-form .btn").click(() => {
this.handleParticipantAdd((userId: number) => {
this.api.addAuthorization({
userId: userId,
simulationId: authorizations[0].simulationId,
authorizationLevel: "VIEW"
});
});
});
this.table.on("click", ".participant-level div", (event: JQueryEventObject) => {
this.handleParticipantLevelChange(event, (authorization: IAuthorization) => {
this.api.updateAuthorization(authorization);
});
});
this.table.on("click", ".participant-remove div", (event: JQueryEventObject) => {
this.handleParticipantDelete(event, (authorization) => {
this.api.deleteAuthorization(authorization);
});
});
this.populateParticipantList();
this.windowOverlay.fadeIn(200);
}
/**
* Shows a window to be used for creating a new project.
*/
public showAddProjectWindow(): void {
this.editMode = false;
this.simAuthorizations = [];
$(".project-name-form .btn").hide();
$(".window .window-heading").text("Create a project");
$(".project-create-open-btn").show().click(() => {
if ($(".project-name-form input").val() === "") {
this.showAlert(".project-name-alert");
return;
}
this.createSimulation((simulationId: number) => {
ProjectsController.openProject({
userId: this.projectsController.currentUserId,
simulationId,
authorizationLevel: "OWN"
});
});
});
$(".project-create-btn").show().click(() => {
if ($(".project-name-form input").val() === "") {
this.showAlert(".project-name-alert");
return;
}
this.createSimulation(() => {
this.projectsController.updateAuthorizations();
this.closeWindow();
});
});
$(".project-cancel-btn").show().click(() => {
this.closeWindow();
});
this.table.empty();
$(".project-name-form input").val("");
$(".participant-add-form input").val("");
$(".participant-add-form .btn").click(() => {
this.handleParticipantAdd(() => {
});
});
this.table.on("click", ".participant-level div", (event: JQueryEventObject) => {
this.handleParticipantLevelChange(event, () => {
});
});
this.table.on("click", ".participant-remove div", (event: JQueryEventObject) => {
this.handleParticipantDelete(event, () => {
});
});
this.windowOverlay.fadeIn(200);
}
/**
* Creates a new simulation with the current name input and all currently present authorizations added in the
* project 'add' window.
*
* @param callback The function to be called when this operation has succeeded
*/
private createSimulation(callback: (simulationId: number) => any): void {
this.api.addSimulation({
id: -1,
name: $(".project-name-form input").val(),
datetimeCreated: Util.getCurrentDateTime(),
datetimeLastEdited: Util.getCurrentDateTime()
}).then((data: any) => {
let asyncCounter = this.simAuthorizations.length;
this.simAuthorizations.forEach((authorization: IAuthorization) => {
authorization.simulationId = data.id;
this.api.addAuthorization(authorization).then((data: any) => {
asyncCounter--;
if (asyncCounter <= 0) {
callback(data.id);
}
});
});
if (this.simAuthorizations.length === 0) {
callback(data.id);
}
});
}
/**
* Displays an alert of the given class name, to disappear again after a certain pre-defined timeout.
*
* @param name A selector that uniquely identifies the alert body to be shown.
*/
private showAlert(name): void {
let alert = $(name);
alert.slideDown(200);
setTimeout(() => {
alert.slideUp(200);
}, 5000);
}
/**
* Closes the window with a transition, and calls the relevant callback after that transition has ended.
*/
private closeWindow(): void {
this.windowOverlay.fadeOut(200, () => {
this.closeCallback();
});
}
/**
* Handles the click on an authorization icon in the project window authorization list.
*
* @param event The JQuery click event
* @param callback The function to be called after the authorization was changed
*/
private handleParticipantLevelChange(event: JQueryEventObject,
callback: (authorization: IAuthorization) => any): void {
$(event.target).closest(".participant-level").find("div").removeClass("active");
$(event.target).addClass("active");
let affectedRow = $(event.target).closest(".participant-row");
for (let level in ProjectsController.authIconMap) {
if (!ProjectsController.authIconMap.hasOwnProperty(level)) {
continue;
}
if ($(event.target).is("." + ProjectsController.authIconMap[level])) {
this.simAuthorizations[affectedRow.index()].authorizationLevel = level;
callback(this.simAuthorizations[affectedRow.index()]);
break;
}
}
}
/**
* Handles the event where a user seeks to add a participant.
*
* @param callback The function to be called if the participant could be found and can be added.
*/
private handleParticipantAdd(callback: (userId: number) => any): void {
let inputForm = $(".participant-add-form input");
this.api.getUserByEmail(inputForm.val()).then((data: any) => {
let insert = true;
for (let i = 0; i < this.simAuthorizations.length; i++) {
if (this.simAuthorizations[i].userId === data.id) {
insert = false;
}
}
let simulationId = this.editMode ? this.simulationId : -1;
if (data.id !== this.projectsController.currentUserId && insert) {
this.simAuthorizations.push({
userId: data.id,
user: data,
simulationId: simulationId,
authorizationLevel: "VIEW"
});
callback(data.id);
Util.sortAuthorizations(this.simAuthorizations);
this.populateParticipantList();
}
// Clear input field after submission
inputForm.val("");
}, (reason: any) => {
if (reason.code === 404) {
this.showAlert(".participant-email-alert");
}
});
}
/**
* Handles click events on the 'remove' icon next to each participant.
*
* @param event The JQuery click event
* @param callback The function to be executed on removal of the participant from the internal list
*/
private handleParticipantDelete(event: JQueryEventObject, callback: (authorization: IAuthorization) => any): void {
let affectedRow = $(event.target).closest(".participant-row");
let index = affectedRow.index();
let authorization = this.simAuthorizations[index];
this.simAuthorizations.splice(index, 1);
this.populateParticipantList();
callback(authorization);
}
/**
* Populates the list of participants in the project edit window with all current authorizations.
*/
private populateParticipantList(): void {
this.table.empty();
this.simAuthorizations.forEach((authorization: IAuthorization) => {
this.table.append(
'
' +
'
' + authorization.user.givenName + ' ' +
authorization.user.familyName + '
' +
'
' +
'
' +
'
'
);
});
}
}