(
/**
* Contains the functionalities related to the manage time slots page.
*
* @module manage_time_slots
* @author Joonas Konki
* @author Anu Koskela
* @author Mikko Kuhno
* @author Henrik Paananen
* @author Atte Räty
* @license BSD 3-clause, see LICENSE for more details.
* @copyright 2015 Kepler project authors
*/
function(){
var timeslots = null;
var currentTime = null;
var cal = null;
/**
* Initialises and updates the calendar.
* @memberof module:manage_time_slots
*/
function updateCalendar() {
if(cal === null) {
initCalendar();
}
cal.fullCalendar('refetchEvents');
}
/**
* Gets the selected calendar timeslot event.
* @memberof module:manage_time_slots
* @param event - Contains the event information.
* @param element - Contains information what kind of.
* element the clicked event is
* @param view - Contains the viewmode in which the element is shown.
*/
function calendarClick (event, element, view) {
if (event.eventTimeslot !== undefined) {
selectCalendarTimeslot(event);
}
}
/**
* Renders the selected timeslots to the calendar.
* @memberof module:manage_time_slots
* @param event - Contains the event information.
* @param element - Contains information what kind of
* element the event is.
* @param view - Contains the viewmode in which the element is shown.
*/
function calendarEventRender(event, element, view) {
calUtil.defaultEventRender(event, element, view);
}
/**
* Initialises the calendar with the given custom attributes.
* @memberof module:manage_time_slots
* @param timeslot - The timeslots to render to the calendar.
* @param data - The data to initialise the calendar with.
*/
function initCalendar(timeslot, data) {
cal = calUtil.initCal(calendarClick, calendarEventRender);
cal.fullCalendar('addEventSource', {
events: function(start, end, timezone, callback) {
var params = {
'start_time': start.toISOString(),
'end_time': end.toISOString()
};
kepler.getCalendarEvents(params, function(data) {
var events = [];
for (var i = 0; i < data.events.length; i++) {
var event = data.events[i];
// console.log(event);
var color = calUtil.colorPalette.reservedGrey;
var pointer = false;
var res_id = null;
if(event.type === 'reservation'){
color = calUtil.colorPalette.lightBlue;
res_id = event.reservation.id;
pointer = true;
}
calEvent = calUtil.makeCalendarEvent(event);
calEvent.color = color;
calEvent.borderColor = calUtil.colorPalette.borderBlue;
calEvent.textColor = 'black';
calEvent.reservation_id = res_id;
calEvent.pointer = pointer;
events.push(calEvent);
}
callback(events);
});
}
});
}
/**
* Empties the supervisor selector and fills it with those supervisors whose
* user role matches the selected study level.
* @memberof module:manage_time_slots
* @param {object} supervisors - A list of all available users who have the user
* role "supervisor".
* @param {string} studyTypeId - The ID of the selected study level.
*/
function updateSupervisors(supervisors, studyTypeId) {
$("#instructorSelection").empty();
for (var i = 0; i < supervisors.length; i++) {
var supervisor = supervisors[i];
for (var k = 0; k < supervisor.roles.length; k++) {
if (supervisor.roles[k].unit_type_id === studyTypeId) {
var opt = $("<option>").attr("value", supervisor.user_id);
opt.text(supervisor.first_names + " " + supervisor.last_name);
$("#instructorSelection").append(opt);
}
}
}
$("#instructorSelection option").first().prop("selected", true);
}
/**
* Empties all of the editable fields related to creating a new reservation.
* Fetches time slots from the database and updates the study level selection.
* @memberof module:manage_time_slots
*/
function updateNewReservationForm() {
kepler.getTimeSlotEditInfo(function (data) {
var unitTypes = data.unit_types;
var supervisors = data.supervisors;
$('#maxRes').val(data.max_reservations_default);
$('#studyLevelSelection').empty();
$("#instructorSelection").empty();
$('#studyLevelSelection').change(function (v) {
var selectedStudyType = parseInt(v.target.value);
updateSupervisors(supervisors, selectedStudyType);
});
for (var i = 0; i < unitTypes.length; i++) {
var opt = $("<option>").attr("value", unitTypes[i].unit_type_id);
opt.text(unitTypes[i].unit_type_name);
$('#studyLevelSelection').append(opt);
}
$('#studyLevelSelection option').first().prop("selected", true);
var sLevelId = parseInt($('#studyLevelSelection').val());
updateSupervisors(supervisors, sLevelId);
});
}
/**
* Returns a list of the selected supervisors.
* @memberof module:manage_time_slots
*/
function getSelectedSupervisors() {
var ins = [];
ins[0] = $("#instructorSelection").val();
//TODO (Anu) This needs to work for multiple supervisors.
return ins;
}
/**
* Gets the information from all editable fields and makes a call to save the
* new time slot with the gathered information.
* @memberof module:manage_time_slots
*/
function saveTimeSlot(){
var date;
var startTime;
var endTime;
var studyLevel;
var maxRes;
var supervisorIds = [];
var status;
date = $("#date").val(); //TODO (Anu) formatting
if($("#timeMorning").is(':checked')) {
startTime = "08:00:00";
endTime = "12:00:00";
}
else if($("#timeMidday").is(':checked')) {
startTime = "12:00:00";
endTime = "16:00:00";
}
else if($("#timeEvening").is(':checked')) {
startTime = "16:00:00";
endTime = "20:00:00";
}
else if($("#timeOther").is(':checked')) {
startTime = $("#timeStart").val();
endTime = $("#timeEnd").val();
}
studyLevel = $("#studyLevelSelection").val();
maxRes = $("#maxRes").val();
supervisorIds = getSelectedSupervisors();
status = $("#statusSelection").val();
var params = {
'start_time': date + "T" + startTime,
'end_time': date + "T" + endTime,
'unit_type_id': studyLevel,
'max_reservations': maxRes,
'time_slot_supervisor_id_list': supervisorIds,
'status': status,
};
if(startTime === null || endTime === null) {
alert(kepler.translate('content.manage_time_slots_time_unclear'));
}
else {
kepler.addTimeSlot(params, function (data) {
kepler.showResult(data.result, "#addTimeSlotNotification");
if (data.result.success) {
reloadTimeSlots();
}
});
}
}
/**
* Displays the students and additional information related to the time slot
* in a list element.
* @memberof module:manage_time_slots
* @param {object} timeslot - The time slot for which the information is
* related to.
* @param {number} index - The index of the wanted unit.
* @param {object} parent - The element where the information is added.
*/
function addExperimentsInfo(timeslot, index, parent){
var studentList = $("<ul>").css("list-style","none");
var experiment = timeslot.reservations[index];
parent.append($("<div>").text(experiment.unit_group_name + "/" +
experiment.unit_qualifier + ", " + experiment.unit_name));
for (var k = 0; k < experiment.user_group.members.length; k++){
var listItem = $("<li>");
var button = $("<button>");
button.addClass("btn btn-xs btn-default").attr("type", "button");
button.attr("data-placement", "bottom");
button.attr("data-toggle", "popover");
button.attr("title", kepler.translate('label.contactInfo'));
var emailText = "";
if (experiment.user_group.members[k].email === ""){
emailText = kepler.translate('label.noContactInfo');
}
else emailText = experiment.user_group.members[k].email;
button.attr("data-content",emailText);
button.append($("<span>").addClass("glyphicon glyphicon-info-sign"));
button.popover();
listItem.append(button);
listItem.append($("<span>").text(" " +
experiment.user_group.members[k].name + " "));
studentList.append(listItem);
}
parent.append(studentList);
}
/**
* An utility function used to cancel the selected time slot.
*
* @function
* @name make_cancelTimeSlot
* @inner
* @memberof module:
* @param {number} tsId - The ID of the selected time slot.
* @param {string} tsName - The header information of the selected
* time slot.
* @returns function
*/
function make_cancelTimeSlot(tsId, tsName) {
return function () {
$("#modalButtonYes").off();
/**
* Makes a call to the database to cancel the current time
* slot.
*
* @function
* @name modalButtonYes click
* @inner
* @memberof module:manage_time_slots
*/
$("#modalButtonYes").click(function () {
console.log("test to remove: " + tsId + ", " + tsName);
//TODO (Anu) Remove console.log when not needed.
kepler.deleteTimeSlot(
{ 'time_slot_id': tsId },
function (data) {
kepler.showResult(data.result, "#notification");
if (data.result.success) {
reloadTimeSlots();
}
}
);
});
$("#modalLabel").text(tsName);
$("#modalCancel").modal('show');
};
}
/**
* Creates a table that displays all the time slots and a toggleable area
* for each of the time slot which have reservations. The toggleable area
* includes the information of the reserved unit groups and of the participants.
* Adds a button and a listener for each upcoming time slot, which enables
* cancelling the time slot.
* @memberof module:manage_time_slots
*/
function initTable(data) {
//TODO (Anu) Editing the time slot
timeslots = data.time_slots;
var tsList = $('#timeSlotList');
// console.log(timeslots);
for (var i = 0; i < timeslots.length; i++) {
var ts = timeslots[i];
var tsDiv = $('<li>').addClass('timeSlot').attr('id',"li" + i);
if (ts.status == 'canceled_id')
tsDiv.addClass('canceled');
var hasReservations = ts.reservations.length !== 0;
var listRow = $('<div>').addClass("list-group-item");
listRow.attr("id", "header" + i);
var noOfExperiments = getNumberOfReservations(ts);
if (ts.status === 'canceled_id') {
listRow.append($("<span>").addClass(
"badge").text(noOfExperiments).css(
"background", "#a94442").css("display", "inline-block"));
listRow.addClass("list-group-item-danger");
listRow.attr("data-toggle", "collapse");
listRow.attr("data-target", "#row" + i).css("cursor","pointer");
listRow.append($("<span>").addClass(
"glyphicon glyphicon-chevron-down").css("float","left").css(
"cursor","pointer"));
} else if (hasReservations) {
listRow.append($("<span>").addClass(
"badge").text(noOfExperiments).css("display", "inline-block"));
listRow.addClass("list-group-item-info");
listRow.attr("data-toggle", "collapse");
listRow.attr("data-target", "#row" + i).css("cursor","pointer");
listRow.append($("<span>").addClass(
"glyphicon glyphicon-chevron-down").css("float","left").css(
"cursor","pointer"));
} else {
listRow.append($("<span>").addClass(
"badge").text(noOfExperiments).css("background", "lightgray").css(
"display", "inline-block"));
listRow.addClass("list-group-item-default");
listRow.attr("data-toggle", "collapse").attr("data-target",
"#row" + i).css("cursor","pointer");
listRow.append($("<span>").addClass(
"glyphicon glyphicon-chevron-down").css("color", "lightgray").css(
"float","left").css("cursor","pointer"));
}
var tsTime = kepler.datetimeIntervalString(ts.start_time, ts.end_time);
var tm_span = $("<div>").text(tsTime);
tm_span.css("display", "inline-block").css("min-width", "12em");
tm_span.css("margin-left", "1em");
listRow.append(tm_span);
var tsName = ts.unit_type_name;
var instructors = "";
for (var k = 0; k < ts.supervisors.length; k++){
if (k > 0) instructors += ",";
if(ts.supervisors[k].call_name !== null)
instructors += " " + ts.supervisors[k].call_name;
else instructors += " " + ts.supervisors[k].first_names;
instructors += " " + ts.supervisors[k].last_name;
}
tsName += ", " + instructors;
listRow.append($("<div>").text(tsName).css("display", "inline-block"));
if (ts.status == 'canceled_id'){
var cancelledSpan =
$("<div>").text(
kepler.translate('content.reservations_cancelled_time_slot'));
cancelledSpan.css("display","inline-block").css("min-width","12em");
cancelledSpan.css("margin-left", "1em");
listRow.append(cancelledSpan);
}
tsDiv.append(listRow);
var collapseRow = $('<div>').addClass('collapse').attr('id',"row" + i);
for (var j = 0; j < ts.reservations.length; j++){
var colUnitGroup = "";
var listItem = $("<li>").addClass("list-group-item");
var helpDiv = $("<div>").addClass("row");
var listDivInfo = $("<div>").addClass("col-sm-6");
addExperimentsInfo(ts, j, listDivInfo);
helpDiv.append(listDivInfo);
if(ts.reservations[j].notes.length !== 0){
var infoDiv = $("<div>").append($("<b>").text(kepler.translate(
'content.reservations_extra_info') + ":"));
for (var l = 0; l < ts.reservations[j].notes.length; l++) {
infoDiv.append($("<br>")).append($("<i>").text(
ts.reservations[j].notes[l].note));
}
helpDiv.append(infoDiv);
}
listItem.append(helpDiv);
collapseRow.append(listItem);
}
if ((ts.status !== 'canceled_id') && (ts.start_time > currentTime))
{
var buttonClass = '';
buttonClass = "class='btn btn-primary'";
var editButton = $("<button id=" + ts.id + " " + buttonClass +
">" + kepler.translate("button.edit") + "</button>");
editButton.click(function(){
notImplementedMsg();
//window.location = '/edit_time_slot?id=' + this.id;
});
var deleteButton = $("<button>").addClass("btn btn-default");
deleteButton.text(kepler.translate("button.delete"));
deleteButton.click(make_cancelTimeSlot(ts.id,tsTime +", "+tsName));
var buttonDiv = $("<div>").attr("align", "right");
buttonDiv.append(editButton);
buttonDiv.append(deleteButton);
collapseRow.append(buttonDiv);
}
tsDiv.append(collapseRow);
tsList.append(tsDiv);
}
}
/**
* Returns the number of reservations made to the given time slot.
* @memberof module:manage_time_slots
* @param {object} timeslot - The current time slot.
* @returns {number} - The number of reservations the time slot has.
*/
function getNumberOfReservations(timeslot){
return timeslot.reservations.length;
}
/**
* Shows the wanted time slots based on which options (past, present, future)
* are checked and hides the rest. If no time slots match the selected time
* frame, shows a notification.
* @memberof module:manage_time_slots
*/
function updateTable(){
var tsList = $('#timeSlotList');
var howManyDisplayed = 0;
var showPast = $('#selectionPast').is(':checked');
var showCurrent = $('#selectionCurrent').is(':checked');
var showFuture =$('#selectionFuture').is(':checked');
function timeSlotVisible(timeSlot) {
return (showPast && timeSlot.end_time < currentTime) ||
(showCurrent && (timeSlot.start_time < currentTime &&
timeSlot.end_time > currentTime) ) ||
(showFuture && timeSlot.start_time > currentTime);
}
for (var i = 0; i < timeslots.length; i++) {
if (timeSlotVisible(timeslots[i])) {
$("#li" + i).show();
howManyDisplayed++;
}
else $("#li" + i).hide();
}
if(howManyDisplayed === 0) {
$("#noMatches").show();
$("#timeSlotList").hide();
}
else {
$("#noMatches").hide();
$("#timeSlotList").show();
}
}
/**
* Gets the time slots from the database and updates the timeSlotList.
* @memberof module:manage_time_slots
*/
function reloadTimeSlots(){
var tsTable = $("#timeSlotList");
tsTable.empty();
var params = {
'only_active': true
};
kepler.getTimeSlots(params, function (data) {
currentTime = data.timestamp;
initTable(data);
updateTable();
$('#displayedSelection').change(function (data) {
updateTable();
});
});
}
/**
* This is executed after the HTML page has been loaded.
* This is a common procedure of all of the client-side modules to
* initialise the page content.
* @memberof module:manage_time_slots
*/
function doc_ready() {
$("#navManageTimeSlots").addClass("active");
reloadTimeSlots();
updateNewReservationForm();
$("#shiftTimeFrame").change(function(v){
notImplementedMsg();
});
$("#saveButton").click(function(){
saveTimeSlot();
});
/**
* Toggles between the calendar and list views when the button is clicked.
*
* @function
* @name toggleCalendarBtn click
* @inner
* @memberof module:manage_time_slots
*/
$("#toggleCalendarBtn").click(function(v) {
if($("#calendar").is(":visible")) {
$("#timeSlotList").show();
$("#calendar").hide();
$("#toggleCalendarBtn").text(
kepler.translate('content.reservation_frame_button_calendar'));
reloadTimeSlots();
} else {
$("#timeSlotList").hide();
$("#calendar").show();
updateCalendar();
$("#toggleCalendarBtn").text(
kepler.translate('content.reservation_frame_button_list'));
}
});
}
$(document).ready(doc_ready);
}());