/**
* Constructs an instance of Kepler API object.
* The object is a general class that is used to make API calls to the server
* side application in all of the modules.
* Each module is a specific JavaScript code that is loaded by the HTML pages.
*
* @constructor
*
* @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 Kepler() {
var kepler = this;
var host = window.location.origin;
/**
* Adds done and fail callbacks to the specified AJAX call.
*/
function addCallbacksToCall(call, callback) {
call.done(function (data, status) {
if (data.status === 'ok') {
console.log(data);
callback(data);
} else if (data.status === 'error') {
//alert("Error: " + data.reason + ": " + data.message);
//console.log("Error: " + data.reason + ": " + data.message);
kepler.showError(data.reason, data.message);
} else {
console.error("Server error: " + status);
}
});
call.fail(function () {
console.error("Could not connect to Kepler");
});
return call;
}
/**
* The primary utility function that makes Kepler AJAX calls
* to the server side application.
*
* @param func - The name of the API function that will be called.
* @param data - The parameters of the function passed as
* the body of POST request.
* @returns Returns the created jQuery AJAX call.
*/
function makeCall(func, callback, params) {
var url = host + '/call/' + func;
console.log('Kepler call: ' + url);
var data = JSON.stringify(params);
//if (data) console.log('params: ' + data);
var call = $.ajax({
type: 'POST',
url: url,
data: data,
contentType: "application/json",
dataType: 'json'
});
return addCallbacksToCall(call, callback);
}
/**
* Shows an error message in the element specified by the ID.
* If no ID is given, the element with ID "#error" is used.
*
* @param {string} reason The reason of the error.
* @param {string} message The error message.
* @param {string} elem_id The element ID where the error should be shown.
*/
this.showError = function(reason, message, elem_id) {
if (elem_id === undefined)
elem_id = '#error';
if (!message)
$(elem_id).text(reason);
else
$(elem_id).text(reason + ": " + message);
};
// Message fade out delay in milliseconds.
var messageDelayMs = 5000;
/**
* Shows the result message in the element specified by the ID.
*
* @param {object} result The Kepler API result object.
* @param {string} elem_id The element ID where the message should be shown.
*/
this.showResult = function(result, elem_id) {
var elem = $(elem_id);
var msg = result.message;
if (!msg) {
if (result.success) {
msg = kepler.translate('msg.success');
} else {
msg = kepler.translate('msg.failure');
}
}
if (result.reason) {
msg += " " + result.reason;
}
if (result.success) {
elem.addClass("bg-success");
elem.removeClass("bg-danger");
} else {
elem.addClass("bg-danger");
elem.removeClass("bg-success");
}
elem.text(msg);
elem.show();
elem.delay(messageDelayMs).fadeOut();
};
/**
* Gets all notice board notes.
*
* @param callback The handler that is called after the request returns.
*/
this.getNoticeBoard = function(callback) {
return makeCall('get_notice_board', callback);
};
/**
* Gets all notice board notes with additional information.
*
* @param callback The handler that is called after the request returns.
*/
this.getNoticeBoardNotes = function(callback) {
return makeCall('get_notice_board_notes', callback);
};
/**
* Adds a new notice board note.
*
* @param callback - The handler that is called after the request returns.
*/
this.addNoticeBoardNote = function(params, callback) {
return makeCall('add_notice_board_note', callback, params);
};
/**
* Edits an existing notice board note.
*
* @param callback - The handler that is called after the request returns.
*/
this.editNoticeBoardNote = function(params, callback) {
return makeCall('edit_notice_board_note', callback, params);
};
/**
* Hides the notice board note.
*
* @param callback - The handler that is called after the request returns.
*/
this.hideNoticeBoardNote = function(params, callback) {
return makeCall('hide_notice_board_note', callback, params);
};
/**
* Shows the notice board note.
*
* @param callback - The handler that is called after the request returns.
*/
this.showNoticeBoardNote = function(params, callback) {
return makeCall('show_notice_board_note', callback, params);
};
/**
* Gets the information related to the current user.
*
* @param callback - The handler that is called after the request returns.
*/
this.getUserInfo = function(callback) {
return makeCall('get_user_info', callback);
};
/**
* Gets all the groups where the current user belongs to.
*
* @param callback - The handler that is called after the request returns.
*/
this.getUserGroups = function(callback) {
return makeCall('get_user_groups', callback);
};
/**
* Creates a new group for the current user.
*
* @param callback - The handler that is called after the request returns.
*/
this.addUserGroup = function(params, callback) {
return makeCall('add_user_group', callback, params);
};
/**
* Deletes (hides) an existing group of the current user from the database.
*
* @param callback - The handler that is called after the request returns.
*/
this.deleteUserGroup = function(params, callback){
return makeCall('delete_user_group', callback, params);
};
/**
* Gets the reservations of the current user.
* @param callback - The handler that is called after the request returns.
* @param err_elem_id - The ID of the element in which possible
* error messages are shown.
*/
this.getReservationsUser = function(callback) {
return makeCall('get_reservations_user', callback);
};
/**
* Gets the list of all units from the database.
* Additionally, returns the list of all unit types in the system.
*
* @param callback - The handler that is called after the request returns.
*/
this.getUnits = function(callback) {
return makeCall('get_units', callback);
};
/**
* Gets the list of all units from the database with additional information
* needed for editing the units.
*
* @param callback - The handler that is called after the request returns.'
*/
this.getUnitsEditable = function(callback) {
return makeCall('get_units_editable', callback);
};
/**
* Edits an existing unit in the database.
*
* @param callback - The handler that is called after the request returns.
*/
this.editUnit = function(params, callback) {
return makeCall('edit_unit', callback, params);
};
/**
* Adds a new unit to the database.
*
* @param callback - The handler that is called after the request returns.
*/
this.addUnit = function(params, callback) {
return makeCall('add_unit', callback, params);
};
/**
* Deletes (hides) an existing unit from the database.
*
* @param callback - The handler that is called after the request returns.
*/
this.deleteUnit = function(params, callback) {
return makeCall('delete_unit', callback, params);
};
/**
* Gets the list of unit groups from the database.
*
* @param callback - The handler that is called after the request returns.
*/
this.getUnitGroups = function(callback) {
return makeCall('get_unit_groups', callback);
};
/**
* Edits an existing unit group in the database.
*
* @param callback - The handler that is called after the request returns.
*/
this.editUnitGroup = function(params, callback) {
return makeCall('edit_unit_group', callback, params);
};
/**
* Adds a new unit group to the database.
*
* @param callback - The handler that is called after the request returns.
*/
this.addUnitGroup = function(params, callback) {
return makeCall('add_unit_group', callback, params);
};
/**
* Deletes (hides) an existing unit group from the database.
*
* @param callback - The handler that is called after the request returns.
*/
this.deleteUnitGroup = function(params, callback) {
return makeCall('delete_unit_group', callback, params);
};
/**
* Gets the list of all resources and their statuses from the database.
*
* @param callback - The handler that is called after the request returns.
*/
this.getResources = function(callback) {
return makeCall('get_resources', callback);
};
/**
* Edits an existing resource in the database.
*
* @param callback - The handler that is called after the request returns.
*/
this.editResource = function(params, callback) {
return makeCall('edit_resource', callback, params);
};
/**
* Adds a new resource to the database.
*
* @param callback - The handler that is called after the request returns.
*/
this.addResource = function(params, callback) {
return makeCall('add_resource', callback, params);
};
/**
* Deletes (hides) an existing resource from the database.
*
* @param callback - The handler that is called after the request returns.
*/
this.deleteResource = function(params, callback) {
return makeCall('delete_resource', callback, params);
};
/**
* Gets the list of time slots optionally filtered by a time span
* and the study level.
*
* @param callback - The handler that is called after the request returns.
*/
this.getTimeSlots = function(params, callback) {
return makeCall('get_time_slots', callback, params);
};
/**
* Adds a new reservable time slot to the database.
*
* @param callback - The handler that is called after the request returns.
*/
this.addTimeSlot = function(params, callback){
return makeCall('add_time_slot', callback, params);
};
/**
* Deletes (hides) an existing reservable time slot to the database.
*
* @param callback - The handler that is called after the request returns.
*/
this.deleteTimeSlot = function(params, callback){
return makeCall('delete_time_slot', callback, params);
};
/** Gets the information needed in the time slot adding and editing view.
*
* @param callback - The handler that is called after the request returns.
*/
this.getTimeSlotEditInfo = function(callback) {
return makeCall('get_time_slot_edit_info', callback);
};
/** Gets the calendar events of the current user.
*
* @param callback - The handler that is called after the request returns.
*/
this.getCalendarEvents = function(params, callback) {
return makeCall('get_calendar_events', callback, params);
};
/** Gets the list of time slot events optionally filtered by
* a time span
* and the specified unit.
*
* @param callback - The handler that is called after the request returns.
*/
this.getTimeSlotEvents = function(params, callback){
return makeCall('get_time_slot_events', callback, params);
};
/** Adds a new reservation for the current user.
*
* @param callback - The handler that is called after the request returns.
*/
this.addReservation = function(params, callback){
return makeCall('add_reservation', callback, params);
};
/** Deletes (hides) an existing reservation from the current user.
*
* @param callback - The handler that is called after the request returns.
*/
this.deleteReservation = function(params, callback){
return makeCall('delete_reservation', callback, params);
};
/** Searches for the user that matches the search string.
* The call returns the user that matches the search string.
* If no user or many users are found the call returns null.
*
* @param params - The email or account name used for searching a user.
* @param callback - The handler that is called after the request returns.
*/
this.searchUser = function(params, callback){
return makeCall('search_user', callback, params);
};
/** Sets the user default language based on the specified locale name.
*
* @param locale_name - The locale name of the language to be set.
* @param callback - The handler that is called after the request returns.
*/
this.setUserLanguage = function(locale_name, callback) {
var params = {'locale_name': locale_name};
return makeCall('set_user_language', callback, params);
};
/** Sets the session language based on the given locale name.
*
* @param locale_name - The locale name of the language to be set.
*/
this.setLanguage = function(locale_name) {
var params = {'locale_name': locale_name};
function callback(data) {
location.reload(true);
}
return makeCall('set_session_language', callback, params);
};
/**
* Returns the parameter with the specified name from the URL
* query parameters.
*
* @param name - The URL query parameter's name.
*/
this.getQueryParam = function(name) {
var queryString = window.location.search.substring(1);
var variables = queryString.split('&');
for (var i = 0; i < variables.length; i++) {
var param = variables[i].split('=');
if (param[0] == name) {
return param[1];
}
}
};
/**
* Returns the dynamic translation matching the given translation ID.
*
* @param translation_id - The translation ID of the translation text.
*/
this.translate = function(translation_id) {
if (_translations[translation_id] === undefined)
return translation_id;
return _translations[translation_id];
};
/**
* Formats a Date object to common Finnish time string representation of
* hours and minutes (HH:mm).
*
* @param date - The Date object to be formatted.
*/
this.datetimeString = function(date) {
// TODO (Anu) Add a separator between date and time.
return date.toLocaleDateString('fi', {hour:'2-digit',minute:'2-digit'});
// return date.toLocaleDateString(navigator.language,
// {hour:'2-digit', minute:'2-digit'});
};
/**
* Formats a Date object to common Finnish date string representation.
*
* @param date - The Date object to be formatted.
*/
this.dateString = function(date) {
return date.toLocaleDateString('fi');
};
/**
* Formats the given Date object to common Finnish time string
* representation.
*
* @param date - The Date object to be formatted.
*/
this.timeString = function(date) {
return date.toLocaleTimeString('fi', {hour:'2-digit',minute:'2-digit'});
};
/**
* Converts a date string to a Date object.
*
* @param date - The date string to be converted.
* @returns The Date object corresponding to given string.
*/
this.stringToDate = function(dateStr) {
return moment(dateStr, moment.ISO_8601).toDate();
};
/**
* The method is used to format ISO8601 date strings to UI strings.
*
* @param date - Either a date string or a Date object.
* @returns The locale formatted time string.
*/
this.formatDate = function(date) {
if (typeof(date) === "string") {
date = kepler.stringToDate(date);
}
return kepler.dateString(date);
};
/**
* The method is used to format ISO8601 date strings to UI strings.
*
* @param date - Either a date string or a Date object.
* @returns The locale formatted time string.
*/
this.formatDatetime = function(date) {
if (typeof(date) === "string") {
date = kepler.stringToDate(date);
}
return kepler.datetimeString(date);
};
/**
* Formats two Date objects to a string representation of a time interval.
*
* @param start - A Date object for the start of the interval.
* @param end - A Date object for the end of the interval.
* @returns A formatted string representing the interval.
*/
this.datetimeIntervalString = function(start, end) {
var start_date = kepler.stringToDate(start);
var end_date = kepler.stringToDate(end);
return kepler.dateString(start_date) + ' ' +
kepler.timeString(start_date) + ' - ' + kepler.timeString(end_date);
};
/**
* Replaces the given element in the HTML page temporarily with a new div
* that contains a gif animation while the data is being fetched from
* the database.
*
* @param elemId - The id of the HTML element where the animation is placed.
* @param loadFunc - The handler that is called after the request returns.
* @returns The original area when a response from the database has
* been received.
*/
this.createLoadElement = function(elemId, loadFunc) {
var parent = $('<div>');
var element = $(elemId);
var loadIndicator = $('<img>');
loadIndicator.attr('src', '/static/ajax-loader.gif');
loadIndicator.css('position', 'absolute');
loadIndicator.hide();
element.replaceWith(parent);
parent.append(element);
parent.append(loadIndicator);
function make_indicatorOffset(loadIndicator, parent) {
return function () {
var par = parent.offset();
var left = par.left+(parent.width()-loadIndicator.width())/2.0;
var top = par.top+(parent.height()-loadIndicator.height())/2.0;
loadIndicator.offset({ left: left, top: top });
};
}
$(window).load(make_indicatorOffset(loadIndicator, parent));
$(window).resize(make_indicatorOffset(loadIndicator, parent));
var par = parent.position();
var left = par.left+(parent.width()-loadIndicator.width())/2.0;
var top = par.top+(parent.height()-loadIndicator.height())/2.0;
loadIndicator.offset({ left: left, top: top });
// make_indicatorOffset(loadIndicator, parent)();
//loadIndicator.load(make_indicatorOffset(loadIndicator, parent));
//loadIndicator.load();
return {
element: element,
loadIndicator: loadIndicator,
load: function () {
loadIndicator.show();
var call = loadFunc(element);
call.always(function () {
//loadIndicator.hide();
loadIndicator.fadeOut();
});
}
};
};
/**
* Creates a clone of an object.
* @param obj - The object that has a tree-like structure.
*/
this.clone = function (obj) {
var copy;
// Handle the 3 simple types, and null or undefined
if (null === obj || "object" != typeof obj) return obj;
// Handle Date
if (obj instanceof Date) {
copy = new Date();
copy.setTime(obj.getTime());
return copy;
}
// Handle Array
if (obj instanceof Array) {
copy = [];
for (var i = 0, len = obj.length; i < len; i++) {
copy[i] = kepler.clone(obj[i]);
}
return copy;
}
// Handle Object
if (obj instanceof Object) {
copy = {};
for (var attr in obj) {
if (obj.hasOwnProperty(attr))copy[attr]=kepler.clone(obj[attr]);
}
return copy;
}
throw new Error("Unable to copy obj! Its type isn't supported.");
};
// Set handler to initialise kepler functionality after document is loaded.
$(document).ready(function() {
// Set handlers for click event to the "change language" links.
$('#lang_fi').click(function() { kepler.setLanguage('fi'); });
$('#lang_en').click(function() { kepler.setLanguage('en'); });
// Set the title of the document based on the current page header.
var pageHeader = $('#pageHeader');
$('title').text("Kepler - " + pageHeader.text());
});
}
// Initialise the instance of Kepler.
var kepler = new Kepler();
// TODO(henrik): Remove alerts when not needed (inline JS in template files).
//==================
function notImplementedMsg() {
alert(kepler.translate('msg.not_implemented'));
}