pit-scheduler
Version:
A complet scheduler build with jQuery and Boostrap
1,137 lines (1,027 loc) • 149 kB
JavaScript
/*
* jQuery pit-Scheduler Plugin v2.0
* https://github.com/chuck-durst/pit-scheduler
*
* Copyright 2016 Charles Durst
* Released under the MIT license
*/
var i18n = {
allowed: [
'en'
],
en: {
day: 'Day',
days: 'Days',
months: 'Months',
list: 'List',
tasks: 'Tasks',
task: 'Task',
hour: 'Hour',
hours: 'Hours',
users: 'Users',
unlisted: 'Unlisted',
settings: 'Settings',
hideEmptyLine: 'Hide lines with no task',
description: 'Description',
assignedUsers: 'assigned users',
assignedUser: 'assigned user',
from: 'From',
to: 'to',
notSpecified: 'Not specified',
disableLabelsMovement: 'Disable labels mouvement',
today: 'Today',
thisWeek: 'This week',
thisMonth: 'This month',
thisYear: 'This year',
personalized: 'Personalized',
selectAll: 'Select all',
always: 'always',
total: 'Total',
usersWhose: 'user(s) with',
cycleWhose: 'cycle(s) with',
inSelectedPeriod: 'in the selected period',
all: 'All',
search: 'Search',
addNewTask: 'Create a new task',
addNewUser: 'Create a new user',
editUser: 'Edit the user',
name: 'Name',
required: 'Required',
color: 'Color',
cancel: 'Cancel',
create: 'Create',
createAndAssign: 'Create and assign',
idAlreadyTaken: 'This ID is already taken',
remove: 'Remove',
assign: 'Assign',
edit: 'Edit',
confirm: 'Confirm',
assignTaskTitle: 'Assign users',
assignUserTitle: 'Assign to a task',
allInputRequired: 'All fields are required',
requiredField: 'That field is required',
userIsAlreadyAssigned: 'is already assigned to this task for this period',
selectUsersToAssign: 'Select the users to assign',
selectTasksToAssign: 'Select the tasks to assign',
editTask: 'Edit a task',
group: 'Group',
groups: 'Groups',
selectGroup: 'Select an existing group',
createNewGroup: 'Create a new group',
or: 'or',
seeAll: 'See all',
allocations: 'allocations',
allocation: 'allocation',
tag: 'Tag',
tags: 'Tags',
tagColor: 'Tag color',
filters: 'Filters',
deleteAll: 'Delete all',
addFilter: 'Create filter',
contains: 'Contains',
notContains: 'Does not contains',
added: 'Added',
active: 'Active',
inactive: 'Inactive',
notif: {
taskCreated: 'The task has been successfully created',
userCreated: 'The user has been successfully created',
taskRemoved: 'The task has been successfully removed',
userRemoved: 'The user has been successfully removed',
usersAssigned: 'users has been assigned to the task',
userAssigned: 'user has been assigned to the task',
userUnassigned: 'has correctly been unassigned',
noUser: '<b>Warning : </b>No user has been set',
noTask: '<b>Warning : </b>No task has been set',
taskNotExist: 'is assigned to an inexistent task',
taskInformationsUpdated: 'The task has been edited',
userHasNoTask: 'is not assigned to any task',
userEdited: 'The user has been successfully edited',
userAssignedTo: 'has been assigned to',
userTaskModified: 'The task will now end the',
filterAdded: 'The filter has been added',
filterEdited: 'The filter has been edited',
filterRemoved: 'The filter has been removed',
allFiltersRemoved: 'All fiters has been removed'
}
}
};
(function ($) {
'use strict';
$.fn.pitScheduler = function (options) {
var $scheduler = $(this);
/********* Settings initialization *********/
options = options || {};
var settings = $.extend({
date: {
current: moment(),
selected: (options.defaultDate && moment(options.defaultDate).isValid() ? moment(options.defaultDate) : moment())
},
locale: (options.locale && i18n.allowed.indexOf(options.locale) != -1 ? options.locale : i18n.allowed[0]), //if no locale is defined, it takes the first allowed one
currentDisplay: (options.defaultDisplay && 'days;months;list'.indexOf(options.defaultDisplay) != -1 ? options.defaultDisplay : 'months'),
projectState : 'production', //debug will log all function calls, development will only log the important ones
tasks: options.tasks || [],
users: options.users || [],
defaultColor: options.defaultColor ||'#00BCD4',
notificationDuration: options.notificationDuration || 4000,
hideEmptyLines: options.hideEmptyLines || true,
undo: [],
resize: {},
filters: []
}, options);
moment.locale(settings.locale);
settings.i18n = (i18n.allowed.indexOf(settings.locale) == -1 ? i18n.en : i18n[settings.locale]);
/* Debug tool */
var log = {
log : function (data) {
if (settings.projectState == 'debug') {
console.log(data);
}
},
warn: function (data) {
if (settings.projectState == 'development') {
console.warn(data);
}
},
info: function (data) {
if (settings.projectState == 'development') {
console.info(data);
}
}
};
/********* Main functions *********/
/**
* Update display view
* @param {String} viewMode: can be 'days', 'months' or 'list'
*/
var updateDisplay = function (viewMode) {
log.info('CALL FUNCTION: updateDisplay: viewMode:' + viewMode);
var scrollTop = $('.pts-scheduler-container').scrollTop();
updateDisplayReset();
switch (viewMode) {
case 'days':
setButtonViewFocus('day');
settings.currentDisplay = 'days';
initMainContent();
updateHeaderDates();
$('.pts-line-title-container div').scrollTop(scrollTop);
break;
case 'months':
setButtonViewFocus('month');
settings.currentDisplay = 'months';
initMainContent();
updateHeaderDates();
$('.pts-line-title-container div').scrollTop(scrollTop);
break;
case 'list':
setButtonViewFocus('list');
settings.currentDisplay = 'list';
$('.pts-btn-next').attr('disabled', 'disabled');
$('.pts-btn-previous').attr('disabled', 'disabled');
$('.pts-header-date-display').css('display', 'none');
$('.pts-column-title-container').css('overflow', 'visible');
$('#header-datetimepicker').data("DateTimePicker").disable();
generateListBaseView();
switchListRange('today');
break;
}
};
/**
* Reset elements content that have been modified
*/
var updateDisplayReset = function () {
log.info('CALL FUNCTION: updateDisplayReset');
closeToolbox();
$('.pts-main-content').empty();
$('.pts-column-title-container > div').empty();
$('.pts-line-title-container').empty();
$('.pts-line-title-container').append($('<div></div>'));
$('.pts-corner-mask').empty();
$('.pts-btn-next').removeAttr('disabled');
$('.pts-btn-previous').removeAttr('disabled');
$('.pts-header-date-display').css('display', 'block');
$('.pts-column-title-container').css('overflow', 'hidden');
};
/**
* Function used to update the header datetimepicker
*/
var updateHeaderDates = function () {
log.log('CALL FUNCTION: updateHeaderDates');
$('#header-datetimepicker').data("DateTimePicker").enable();
$('.pts-header-date-display').empty();
switch (settings.currentDisplay) {
case 'days':
$('.pts-header-date-display').append(moment(settings.date.selected).locale(settings.locale).format('LL'));
break;
case 'months':
$('.pts-header-date-display').append(moment(settings.date.selected).locale(settings.locale).format('MMMM YYYY'));
break;
case 'list':
$('.pts-header-date-display').append(moment(settings.date.selected).locale(settings.locale).format('LL'));
break;
}
};
/**
* Launch all the main generations
*/
var initMainContent = function () {
log.info('CALL FUNCTION: initMainContent');
generateBaseView();
generateTableLines();
initGroup();
generateGroupMainContent();
generateUsersList();
updateDatePicker();
};
/**
* Set the focus on the right view mode button
* @param {String} viewMode: can be 'days', 'months' or 'list'
*/
var setButtonViewFocus = function (viewMode) {
$('.pts-header-right-container button').removeClass('pts-active');
$('.pts-header-right-container .pts-btn-' + viewMode + '-view').addClass('pts-active');
};
/**
* Init function that saves users index into associated tasks
*/
var getUsersTasksInTasks = function () {
log.info('CALL FUNCTION: getUsersTasksInTasks');
if (!settings.tasks || settings.tasks.length == 0) return generateNotification('danger', settings.i18n.notif.noTask);
settings.tasks.forEach(function (task) {
task = generateTaskInTask(task);
});
};
/**
* Add an index list of the assigned users of the task
* @param {Object} task
* @returns {Object} task
*/
var generateTaskInTask = function (task) {
log.log('CALL FUNCTION: generateTaskInTask: task: ' + task.name);
task.users = {};
if (! settings.users) return generateNotification('danger', settings.i18n.notif.noUser );
if (!task.color) task.color = (settings.defaultColor ? settings.defaultColor : '#00bdd6');
settings.users.forEach(function (user, userIndex) {
user.index = userIndex;
if (user.tasks) {
user.tasks.forEach(function (userTask, taskIndex) {
if (userTask.id === task.id) {
if (!task.users[userIndex]) {
task.users[userIndex] = [];
}
task.users[userIndex].push(taskIndex);
}
});
}
});
return task;
};
/**
* Generates the groups panels
*/
var initGroup = function () {
log.info('CALL FUNCTION: initGroup');
if ($('.pts-line-group-container').length || !settings.users) return;
settings.defaultGroupName = (settings.defaultGroupName ? settings.defaultGroupName : settings.i18n.unlisted);
settings.groups = [settings.defaultGroupName];
settings.users.forEach(function (user, i) {
if (user.group === undefined || user.group === '') {
user.group = settings.defaultGroupName;
}
else if (settings.groups.indexOf(user.group) == -1) {
settings.groups.push(user.group);
}
});
settings.groups.unlisted = 0; //stores the id of the unlisted group
settings.groups.added = [];
settings.groups.forEach(function (e, i) {
var usersInGroup = getUsersInGroup(e);
if (usersInGroup.length > 0) {
var mustBeShowed = false;
usersInGroup.forEach(function (userIndex) {
if (settings.users[userIndex] && settings.users[userIndex].isShowed == true) {
mustBeShowed = true;
}
});
if (mustBeShowed) {
generateGroupTab(e, i);
}
}
});
};
/**
* Returns the real length of an array
* @param {Object | Array} arr
* @returns {Number} The real object length
*/
var getLength = function (arr) {
return Object.keys(arr).length;
};
/**
* Init all the users
*/
var initUsers = function () {
log.info('CALL FUNCTION: initUsers');
if (!settings.users) return;
settings.users.forEach(function (user, i) {
initUser(user, i);
});
};
/**
* Used to clone an array and all the data it contains
* @param {Array | Object} origin
* @returns {Array | Object} cloned
*/
var clone = function (origin) {
var cloned = (origin instanceof Array) ? [] : {};
for (var i in origin) {
if (i == 'clone') continue;
if (origin[i] && typeof origin[i] == "object") {
cloned[i] = clone(origin[i]);
} else {
cloned[i] = origin[i]
}
}
return cloned;
};
/**
* Returns a temporary object that contains the data required to make an undo
* @returns {Object} contains the saved data
*/
var getUndo = function () {
if (settings.disableUndo == true) return null;
return {
tasks: clone(settings.tasks),
users: clone(settings.users),
groups: clone(settings.groups)
};
};
/**
* Add some useful data to an user
* @param {Object} user
* @param {Number} index of the user
*/
var initUser = function (user, index) {
user.isShowed = userLineIsShowed(user);
user.lineHeight = getUserLineHeight(user);
user.index = index;
};
/**
* Update the content of the datepicker
*/
var updateDatePicker = function () {
log.log('CALL FUNCTION: updateDatePicker');
$('#header-datetimepicker').datetimepicker()
.data('DateTimePicker').locale(settings.locale)
.defaultDate(settings.date.selected)
.date(settings.date.selected)
.viewDate(settings.date.selected)
.enabledHours(false)
.format((settings.currentDisplay === 'months' ? 'MM/YYYY' : 'L'))
.viewMode((settings.currentDisplay === 'months' ? 'months' : 'days'));
};
/**
* Go to the next month/day
*/
var goForward = function () {
log.info('CALL FUNCTION: goForward');
closeToolbox();
if (settings.currentDisplay == 'months') {
settings.date.selected = moment(settings.date.selected).add(1, 'months');
} else {
settings.date.selected = moment(settings.date.selected).add(1, 'day');
}
generateTableLines();
generateGroupMainContent();
generateUsersList();
updateHeaderDates();
updateDatePicker();
};
/**
* Go to the previous month/day
*/
var goBackward = function () {
log.info('CALL FUNCTION: goBackward');
closeToolbox();
if (settings.currentDisplay == 'months') {
settings.date.selected = moment(settings.date.selected).add(-1, 'months');
} else {
settings.date.selected = moment(settings.date.selected).add(-1, 'day');
}
generateTableLines();
generateGroupMainContent();
generateUsersList();
updateHeaderDates();
updateDatePicker();
};
/**
* Shows or hides the pre-loader spinner
* @returns {{show: show, hide: hide}}
*/
var spinner = function () {
var $spinner = $('#pts-spinner-container');
return {
show: function () {
if (settings.hideSpinner) return;
$spinner.css('display', 'block');
},
hide: function () {
if (settings.hideSpinner) return;
$spinner.css('display', 'none');
}
}
};
/**
* Returns true if the first date contains the second one
* @param {Object} origin
* @param {Object} date
* @returns {Boolean}
*/
var isDateInDate = function (origin, date) {
log.log('CALL FUNCTION: isDateInDate');
if ((moment(date.start_date) <= moment(origin.start_date) && moment(date.end_date) >= moment(origin.end_date))
|| (moment(date.start_date) >= moment(origin.start_date) && moment(date.start_date) <= moment(origin.end_date))
|| (moment(date.end_date) <= moment(origin.end_date) && moment(date.end_date) >= moment(origin.start_date))) {
return true;
}
return false;
};
/**
* Returns a task from its Id
* @param {String] taskId
* @returns {Object} the task
*/
var getTaskById = function (taskId) {
log.log('CALL FUNCTION: getTaskById: taskId: ' + taskId);
if (!settings.tasks) return;
var task;
settings.tasks.forEach(function (_task) {
if (_task.id === taskId) {
task = _task;
}
});
return task;
};
/**
* Return true if the user has tasks in the selected month/day
* @param {Object} user
* @returns {Boolean}
*/
var userHasTask = function (user) {
log.log('CALL FUNCTION: userHasTask: user: ' + user.name);
var response = false;
var originDates = {
start_date: (settings.currentDisplay == 'days' ? moment(settings.date.selected).startOf('day') : moment(settings.date.selected).startOf('month')),
end_date: (settings.currentDisplay == 'days' ? moment(settings.date.selected).endOf('day') : moment(settings.date.selected).endOf('month'))
};
user.tasks.forEach(function (task) {
if (isDateInDate(originDates, task) == true) {
response = true;
}
});
return response;
};
/**
* Get the height of an user line
* @param {Object} user
* @returns {Number}
*/
var getUserLineHeight = function (user) {
log.log('CALL FUNCTION: getUserLineHeight: user: ' + user.name);
var tasks = [];
var lineIsHidden = user.isShowed;
var originDates = {
start_date: (settings.currentDisplay == 'days' ? moment(settings.date.selected).startOf('day') : moment(settings.date.selected).startOf('month')),
end_date: (settings.currentDisplay == 'days' ? moment(settings.date.selected).endOf('day') : moment(settings.date.selected).endOf('month'))
};
user.tasks.forEach(function (task) {
var original = getTaskById(task.id);
if (getFiltersResponse('task', original.name) == false && getFiltersResponse('tag', original.tag) == false) {
if (settings.hideEmptyLines && tasks.indexOf(task.id) < 0 && isDateInDate(originDates, task) == true) {
tasks.push(task.id);
} else if (!settings.hideEmptyLines && tasks.indexOf(task.id) < 0 && lineIsHidden == true) {
tasks.push(task.id);
}
}
});
return tasks.length * 40;
};
/**
* Return true if the user line must be showed
* @param {Object} user
* @returns {Boolean}
*/
var userLineIsShowed = function (user) {
log.log('CALL FUNCTION: userLineIsShowed: user: ' + user.name);
if (getFiltersResponse('group', user.group)) return false;
if (getFiltersResponse('user', user.name)) return false;
var response = 0,
originDates = {
start_date: (settings.currentDisplay == 'days' ? moment(settings.date.selected).startOf('day') : moment(settings.date.selected).startOf('month')),
end_date: (settings.currentDisplay == 'days' ? moment(settings.date.selected).endOf('day') : moment(settings.date.selected).endOf('month'))
};
if (!user.tasks) return generateNotification('warning', '<b>' + user.name + '</b> ' + settings.i18n.notif.userHasNoTask);
user.tasks.forEach(function (task) {
var original = getTaskById(task.id)
if (isDateInDate(originDates, task) && getFiltersResponse('task', original.name) == false && getFiltersResponse('tag', original.tag) == false) response++;
});
return ((response > 0) || settings.hideEmptyLines === false);
};
/**
* Moves the tasks labels on horizontal scroll
*/
var setTaskLabelPosition = function () {
log.log('CALL FUNCTION: setTaskLabelPosition');
if (settings.disableLabelsMovement) return;
var $elements = $('.pts-line-marker:has(> .pts-line-marker-label)'),
limit = parseInt($('.pts-line-title-container').offset().left + $('.pts-line-title-container').width());
$.each($elements, function() {
var $label = $(this).children('p'),
right = parseInt($(this).offset().left) + parseInt($(this).width()) - parseInt($label.width()),
left = parseInt($(this).offset().left);
if (left < limit && right > limit + 20) {
$label.css('left', $('.pts-scheduler-container').scrollLeft() - parseInt($(this).css('left')) + 10);
} else {
$label.css('left', '10px');
}
});
};
/**
* Returns an array of the users index that are in the specified group
* @param {String} groupName
* @returns {Array}
*/
var getUsersInGroup = function (groupName) {
log.log('CALL FUNCTION: getUsersInGroup: groupName' + groupName);
var inGroup =[];
settings.users.forEach(function (user) {
if (user.group == groupName) {
inGroup.push(user.index);
}
});
return inGroup;
};
/**
* Opens the toolbox panel
* @param {String} taskId
* @param {Number} userIndex
* @param {String} viewType
*/
var openToolbox = function (taskId, userIndex, viewType) {
log.info('CALL FUNCTION: openToolbox: taskId: ' + taskId + ': userIndex: ' + userIndex + ': viewType: ' + viewType);
var $toolbox = $('#pts-toolbox-container');
$toolbox.empty();
$toolbox.scrollTop();
switch (viewType) {
case 'task':
var task = getTaskById(taskId),
$markers = $('.pts-line-marker');
generateToolboxContentTask(task, settings.users[userIndex]);
$.each($markers, function () {
$(this).css('background-color', getTaskById($(this).attr('data-task')).color);
if ($(this).attr('data-task') !== taskId) {
$(this).css('background-color', '#8e8e8e');
}
});
$('.pts-main-group-column').css('background-color', '#eee');
$toolbox.attr('data-toggle', 'opened');
break;
case 'user':
var user = settings.users[userIndex];
generateToolboxContentUser(user);
$toolbox.attr('data-toggle', 'opened');
break;
case 'createTask':
generateToolboxContentCreateTask();
$toolbox.attr('data-toggle', 'opened');
break;
case 'assignTask':
generateToolboxContentAssignTask(taskId);
$toolbox.attr('data-toggle', 'opened');
break;
case 'editTask':
generateToolboxContentEditTask(taskId);
$toolbox.attr('data-toggle', 'opened');
break;
case 'createUser':
generateToolboxContentCreateUser();
$toolbox.attr('data-toggle', 'opened');
break;
case 'editUser':
var user = settings.users[userIndex];
generateToolboxContentEditUser(user);
$toolbox.attr('data-toggle', 'opened');
break;
case 'assignUser':
var user = settings.users[userIndex];
generateToolboxContentAssignUser(user);
$toolbox.attr('data-toggle', 'opened');
break;
case 'seeAll':
generateToolboxContentSeeAll();
$toolbox.attr('data-toggle', 'opened');
break;
case 'filters':
generateToolboxContentFilters();
$toolbox.attr('data-toggle', 'opened');
break;
default:
return;
}
$toolbox.animate({
width: '460px'
}, 300);
getContrastedColor();
};
/**
* Closes the toolbox panel
*/
var closeToolbox = function () {
log.info('CALL FUNCTION: closeToolbox');
var $toolbox = $('#pts-toolbox-container'),
$markers = $('.pts-line-marker');
if ($toolbox.attr('data-toggle') === 'closed') return;
$.each($markers, function () {
var task = getTaskById($(this).attr('data-task'));
$(this).css('background-color', (task ? task.color : settings.defaultColor));
});
$('.pts-main-group-column').css('background-color', '#fff');
$toolbox.animate({
width: '0%'
}, 300);
$toolbox.attr('data-toggle', 'closed');
$toolbox.empty();
getContrastedColor();
};
/**
* Mixes the overlaid tasks
* @param {String} originIndex: The index of the task
* @param {Object} task: the task to check from
* @param {Object} user: the owner of the task
* @returns {Object} the mixed (or not) task
*/
var hideTaskSuperposition = function (originIndex, task, user) {
log.log('CALL FUNCTION: hideTaskSuperposition: originIndex: ' + originIndex + ':task: ' + task.name + ': user: ' + user.name);
user.tasks.forEach(function (userTask, index) {
if (userTask.id === task.id && index !== originIndex) {
if (moment(task.start_date).format('YYMMDD') == moment(userTask.end_date).format('YYMMDD')&&
((moment(task.start_date).format('H') <= 12 && moment(userTask.end_date).format('H') <= 12 && moment(userTask.end_date).format('H') > 0) ||
(moment(task.start_date).format('H') > 12 && moment(userTask.end_date).format('H') > 12))) {
task.superposed = 'border-left: 2px dotted #000';
}
}
});
return task;
};
/**
* Replaces all elements with the class pts-check-color color
* depending on their background color and their contrast
*/
var getContrastedColor = function () {
log.log('CALL FUNCTION: getContrastedColor');
$('.pts-check-color').each(function () {
var rgb = $(this).css('background-color').match(/^rgb\((\d+),\s*(\d+),\s*(\d+)\)$/);
if (rgb && rgb.length == 4) {
var L = (rgb[1] * 0.299 + rgb[2] * 0.587 + rgb[3] * 0.114) / 255;
if (L > 0.60) {
$(this).children().css('color', '#000');
$(this).css('color', '#000');
$(this).css('border-color', '#000');
}
else {
$(this).children().css('color', '#fff');
$(this).css('color', '#fff');
$(this).css('border-color', '#fff');
}
}
});
};
/**
* Changes the selected list view date range
* @param {String} range: the range to display
*/
var switchListRange = function (range) {
log.log('CALL FUNCTION: switchListRange: range: ' + range);
$('.pts-list-tasks-container').empty();
switch (range) {
case 'all':
settings.list.start_date = moment();
settings.list.end_date = moment();
var $content = '<h4 style="margin:0 0 15px 15px"><b>' + settings.i18n.all + ' :</b></h4>';
$('.pts-list-tasks-container').append($content);
break;
case 'today':
settings.list.start_date = moment().startOf('day');
settings.list.end_date = moment().endOf('day');
var $content = '<h4 style="margin:0 0 15px 15px"><b>' + settings.i18n.from + '</b> ' + settings.list.start_date.locale(settings.locale).format('lll') +
' <b>' + settings.i18n.to + '</b> ' + settings.list.end_date.locale(settings.locale).format('lll') + ' :</h4>';
$('.pts-list-tasks-container').append($content);
break;
case 'week':
settings.list.start_date = moment().startOf('week');
settings.list.end_date = moment().endOf('week');
var $content = '<h4 style="margin:0 0 15px 15px"><b>' + settings.i18n.from + '</b> ' + settings.list.start_date.locale(settings.locale).format('lll') +
' <b>' + settings.i18n.to + '</b> ' + settings.list.end_date.locale(settings.locale).format('lll') + ' :</h4>';
$('.pts-list-tasks-container').append($content);
break;
case 'month':
settings.list.start_date = moment().startOf('month');
settings.list.end_date = moment().endOf('month');
var $content = '<h4 style="margin:0 0 15px 15px"><b>' + settings.i18n.from + '</b> ' + settings.list.start_date.locale(settings.locale).format('lll') +
' <b>' + settings.i18n.to + '</b> ' + settings.list.end_date.locale(settings.locale).format('lll') + ' :</h4>';
$('.pts-list-tasks-container').append($content);
break;
case 'year':
settings.list.start_date = moment().startOf('year');
settings.list.end_date = moment().endOf('year');
var $content = '<h4 style="margin:0 0 15px 15px"><b>' + settings.i18n.from + '</b> ' + settings.list.start_date.locale(settings.locale).format('lll') +
' <b>' + settings.i18n.to + '</b> ' + settings.list.end_date.locale(settings.locale).format('lll') + ' :</h4>';
$('.pts-list-tasks-container').append($content);
break;
case 'personalized':
var $content = '<h4 style="margin:0 0 15px 15px"><b>' + settings.i18n.from + '</b> ' + settings.list.start_date.locale(settings.locale).format('lll') +
' <b>' + settings.i18n.to + '</b> ' + settings.list.end_date.locale(settings.locale).format('lll') + ' :</h4>';
$('.pts-list-tasks-container').append($content);
break;
}
settings.tasks.forEach(function (task) {
if ($('.pts-list-task-enabler-input[data-task=' + task.id + ']').is(':checked')) {
generateListTaskContent(task);
}
});
};
/**
* Creates a new task
* @param {String} name
* @param {String} id
* @param {String} description
* @param {String} color
* @param {Object} tag: contains the tag informations (name and color)
* @param {Boolean} assign: true if the task must be assigned after being created
*/
var createNewTask = function (name, id, description, color, tag, assign) {
log.info('CALL FUNCTION: createNewTask');
var undo = getUndo();
var newTask = {
id: (id.length > 0 ? id : generateRandomId()),
name: name,
description: (description.length > 0 ? description : ''),
color: (color.length > 0 ? color : settings.defaultColor),
tag: tag.name,
tagColor: tag.color
};
newTask = generateTaskInTask(newTask);
settings.tasks.push(newTask);
updateDisplay(settings.currentDisplay);
generateNotification('success', settings.i18n.notif.taskCreated + ' : <b>' + newTask.name + '</b>', undo, settings.onTaskCreation);
if (assign == true) return openToolbox(newTask.id, null, 'assignTask');
};
/**
* Generates a random Id
* @returns {String}
*/
var generateRandomId = function () {
log.log('CALL FUNCTION: generateRandomId');
var S4 = function() {
return (((1+Math.random())*0x10000)|0).toString(16).substring(1);
};
return (S4()+S4()+"-"+S4()+"-"+S4()+"-"+S4()+"-"+S4()+S4()+S4());
};
/**
* Removes a task
* @param {String} taskId
*/
var removeTask = function (taskId) {
log.info('CALL FUNCTION: removeTask');
var undo = getUndo();
$.each(settings.tasks, function (i, task) {
if (task && task.id === taskId) {
delete settings.tasks[i];
}
});
$.each(settings.users, function (userIndex, user) {
if (user) {
$.each(user.tasks, function (taskIndex, task) {
if (task && task.id === taskId) {
delete settings.users[userIndex].tasks[taskIndex];
}
});
}
});
updateDisplay(settings.currentDisplay);
generateNotification('success', settings.i18n.notif.taskRemoved, undo, settings.onTaskRemoval);
};
/**
* Assigns users to a specific task
* @param {Array} users: the users index
* @param {Object} task: the task to assign too
* @param {Date} start_date
* @param {Date} end_date
*/
var assignUsersToTask = function (users, task, start_date, end_date) {
log.info('CALL FUNCTION: assignUsersToTask');
var undo = getUndo();
var taskDates = {
start_date: start_date,
end_date: end_date
};
$('#pts-assign-task-err').empty();
if (!users || !task || !start_date || ! end_date) return;
users.forEach(function (userIndex) {
var user = settings.users[userIndex],
taskExist = false;
user.tasks.forEach(function (_task) {
if (_task.id === task.id && (isDateInDate(_task, taskDates) || isDateInDate(taskDates, _task))) {
taskExist = true;
}
});
if (taskExist) {
return $('#pts-assign-task-err').append('<b>' + user.name + '</b> ' + settings.i18n.userIsAlreadyAssigned + '<br>');
}
user.tasks.push({
id: task.id,
start_date: moment(start_date).format('YYYY-MM-DD HH:mm'),
end_date: moment(end_date).format('YYYY-MM-DD HH:mm')
});
generateTaskInTask(task);
if ($('.pts-toolbox-user[data-user=' + user.index + ']').length == 0) {
var $head = '<hr><div class="pts-toolbox-user animated fadeIn" data-user="' + user.index + '"><h4 class=" text-semibold heading-divided">' + user.name + '</h4>' +
'<table><tbody class="pts-toolbox-user-list" data-head="' + user.index + '"></tbody></table></div>';
$('#pts-toolbox-container > .panel-body').append($head);
}
var $userTasks = ['<tr class="animated fadeIn"><td>',
'<i class="glyphicon glyphicon-trash pts-task-assign-delete-user" data-user="' + user.index + '" data-task="' + task.id + '" data-task-index="' + (user.tasks.length - 1) + '"></i>',
'<b>' + settings.i18n.from + '</b> ' + moment(start_date).locale(settings.locale).format('llll'),
' <b>' + settings.i18n.to + '</b> ' + moment(end_date).locale(settings.locale).format('llll') + '</td></tr>'].join('\n');
$('.pts-toolbox-user-list[data-head=' + user.index + ']').append($userTasks);
$('#pts-toolbox-container').scrollTop($('#pts-toolbox-container')[0].scrollHeight);
});
generateNotification('success', '<b>' + users.length + '</b> ' + ( users.length > 1 ? settings.i18n.notif.usersAssigned: settings.i18n.notif.userAssigned) + ' <b>' + task.name + '</b>',
undo, settings.onTaskAssignation);
};
/**
* Assigns tasks to a specific user
* @param {Object} user
* @param {Array} tasks
* @param {Date} start_date
* @param {Date} end_date
*/
var assignTasksToUser = function (user, tasks, start_date, end_date) {
log.info('CALL FUNCTION: assignTasksToUser');
var undo = getUndo();
if (!user || !tasks || !start_date || ! end_date) return;
$('#pts-assign-user-err').empty();
var taskDates = {
start_date: start_date,
end_date: end_date
};
tasks.forEach(function (taskId) {
var task = getTaskById(taskId),
taskExist = false;
user.tasks.forEach(function (_task) {
if (_task.id === task.id && (isDateInDate(_task, taskDates) || isDateInDate(taskDates, _task))) {
taskExist = true;
}
});
if (taskExist) {
return $('#pts-assign-user-err').append('<b>' + user.name + '</b> ' + settings.i18n.userIsAlreadyAssigned + '<br>');
}
user.tasks.push({
id: task.id,
start_date: moment(start_date).format('YYYY-MM-DD HH:mm'),
end_date: moment(end_date).format('YYYY-MM-DD HH:mm')
});
generateTaskInTask(task);
if ($('.pts-toolbox-task-header[data-task=' + task.id + ']').length == 0) {
var $head = ['<p class="animated fadeIn pts-check-color progress-bar-striped pts-toolbox-task-header" style="background-color:' + task.color + ';margin-top:10px" data-task="' + task.id + '" data-user="' + user.index + '"><b>',
task.name + '</b></p><table style="position: relative;left:30px;"><tbody class="pts-user-sorted-task" data-task="' + task.id + '" class="pts-toolbox-user-list" data-head="' + user.index + '">',
'</tbody></table>'].join('\n');
$('.pts-toolbox-user-list').append($head);
}
var $line = '<tr><td><i class="animated fadeIn glyphicon glyphicon-trash pts-task-assign-delete-user" data-user="' + user.index + '" data-task="' + task.id + '" data-task-index="' + task.index + '"></i>' +
'<b>' + settings.i18n.from + '</b> ' + moment(start_date).locale(settings.locale).format('lll') + ' <b>' + settings.i18n.to + '</b> ' + moment(end_date).locale(settings.locale).format('lll') + '</td></tr>';
$('.pts-user-sorted-task[data-task=' + task.id + ']').append($line);
$('#pts-toolbox-container').scrollTop($('#pts-toolbox-container')[0].scrollHeight);
});
generateNotification('success', '<b>' + user.name + '</b> ' + settings.i18n.notif.userAssignedTo + ' <b>' + tasks.length + '</b> ' + (tasks.length > 1 ? settings.i18n.tasks : settings.i18n.task),
undo, settings.onTaskAssignation);
};
/**
* Removes a task line from a user
* @param {Object} user
* @param {Object} task
* @param {Number} taskIndex
* @param {Object} undo
*/
var deleteTaskFromUser = function (user, task, taskIndex, undo) {
log.info('CALL FUNCTION: deleteTaskFromUser');
var undo = undo || getUndo();
if (!user.tasks[taskIndex]) return;
delete user.tasks[taskIndex];
generateTaskInTask(task);
initUsers();
initGroup();
generateNotification('success', '<b>' + user.name + '</b> ' + settings.i18n.notif.userUnassigned, undo, settings.onUserTaskDeletion);
};
/**
* Edited the information of an existing task
* @param {Object} task
* @param {Array} newData
*/
var editTask = function (task, newData) {
log.info('CALL FUNCTION: editTask');
var undo = getUndo();
task.name = (newData.name || task.name);
task.color = (newData.color || task.color);
task.description = (newData.description || '');
task.tag = (newData.tag || '');
task.tagColor = (newData.tagColor || '');
updateDisplay(settings.currentDisplay);
generateNotification('success', settings.i18n.notif.taskInformationsUpdated, undo, settings.onTaskEdition);
};
/**
* Creates a new user
* @param {String} name
* @param {String} group
* @param {Boolean} assign: true if the user must be assigned after being created
*/
var createNewUser = function (name, group, assign) {
log.info('CALL FUNCTION: createNewUser');
var undo = getUndo();
settings.users.push({
name: name,
group: (group ? group : ''),
tasks: []
});
var userIndex = settings.users.length - 1;
initUser(settings.users[userIndex], settings.users.length - 1);
generateNotification('success', settings.i18n.notif.userCreated + ' : <b>' + name + '</b>', undo, settings.onUserCreation);
if (assign == true) return openToolbox(null, userIndex, 'assignUser');
updateDisplay(settings.currentDisplay);
};
/**
* Removes a user
* @param {Object} user
*/
var removeUser = function (user) {
var undo = getUndo();
delete settings.users[user.index];
updateDisplay(settings.currentDisplay);
getUsersTasksInTasks();
generateNotification('success', settings.i18n.notif.userRemoved, undo, settings.onUserRemoval);
};
/**
* Edited a user
* @param {Number} userIndex
* @param {Array} newData
*/
var editUser = function (userIndex, newData) {
if (!settings.users[userIndex]) return;
var undo = getUndo();
settings.users[userIndex].name = newData.name;
settings.users[userIndex].group = (newData.group ? newData.group : '');
initUsers();
updateDisplay(settings.currentDisplay);
generateNotification('success', settings.i18n.notif.userEdited, undo, settings.onUserEdition);
};
/**
* update a task when it has been resized
*/
var resizeTask = function () {
clearInterval(settings.resize.timeout);
settings.users[settings.resize.user].tasks.forEach(function (task, taskIndex) {
if (task.id == settings.resize.task && moment(task.end_date).format('YYYYMMDD') == moment(settings.resize.end_date).format('YYYYMMDD')) {
var undo = getUndo();
var count = settings.resize.count;
var splitted = (settings.currentDisplay == 'months' ?
(moment(task.end_date).format('H') <= 12 && parseInt(moment(task.end_date).format('Hmm')) > 0? true : false) :
(moment(task.end_date).format('mm') <= 30 && parseInt(moment(task.end_date).format('mm')) > 0 ? true : false));
task.end_date = moment(task.end_date).add((count * (settings.currentDisplay == 'months' ? 1440 : 60)) , 'minute');
if ((splitted && count % 1 !== 0) || (!splitted && count % 1 == 0)) { //On main border
if (moment(task.end_date).format('HHmm') != '0000') {
task.end_date = (settings.currentDisplay == 'months' ? moment(task.end_date).endOf('day') : moment(task.end_date));
} else {
task.end_date = (settings.currentDisplay == 'months' ? moment(task.end_date).add(-1, 'minute') : moment(task.end_date));
}
} else {
task.end_date = (settings.currentDisplay == 'months' ? moment(task.end_date).hours(12).minutes(0) : moment(task.end_date).minutes(30));
}
task.end_date = moment(task.end_date).format('YYYY-MM-DD HH:mm');
if (parseInt(moment(task.start_date).format('YYYYMMDDHHmm')) >= parseInt(moment(task.end_date).format('YYYYMMDDHHmm'))) {
deleteTaskFromUser(settings.users[settings.resize.user], task, taskIndex, undo);
} else {
generateNotification('success', settings.i18n.notif.userTaskModified + ': <b>' + moment(task.end_date).locale(settings.locale).format('LLLL') + '</b>', undo, settings.onUserEdition);
}
updateDisplay(settings.currentDisplay);
}
});
settings.resize = {};
};
/**
* apply the task resizing
* @param e: the action event
*/
var moveTaskResize = function (e) {
var $taskMarker = settings.resize.element;
$('.pts-task-tooltip').remove();
var overlapse = false;